DEV Community

Cover image for Stop trusting your .env file
Samuel Fontebasso
Samuel Fontebasso

Posted on

Stop trusting your .env file

A personal take on how I stopped shipping broken Vite builds by validating environment variables before the build even starts. No JSON schema, no magic — just JavaScript and clear rules.

A blunt tool for a stupidly common problem

After building more React apps with Vite than I care to admit, I noticed a recurring theme: most of the time, what broke wasn't the code — it was the environment.

A missing VITE_ variable. A malformed URL. A boolean that was actually a string. A Docker ARG that never made it to the final build. And of course, the worst kind: it didn't crash the build... it crashed the user experience.

I got tired of catching these bugs in staging (or worse, production), so I built a tool that would blow up my build early — on purpose.

It's called envguardr, and it's dead simple.

The problem with Vite and environment variables

Vite helpfully injects any variable prefixed with VITE_ into import.meta.env, but:

  1. It doesn't check if the variable is actually defined.
  2. It doesn't validate types.
  3. It assumes everything is a string, and that's your problem now.

You can write if (VITE_ENABLE_FEATURE) and end up with true, "true", "banana", or undefined — and Vite will happily compile it.

What I use now (and why it finally works)

My stack: React + Vite frontend, Nginx for static serving, Docker multistage for builds. Nothing exotic. What changed was the discipline — and the tooling.

Here’s how I validate my environment before anything gets built:

// env.schema.js
export default {
  VITE_API_URL: { type: 'url', required: true },
  VITE_APP_VERSION: { type: 'string', required: true },
  VITE_APP_ENV: { 
    type: { enum: ['staging', 'production'] },
    default: 'production' 
  },
}
Enter fullscreen mode Exit fullscreen mode

That’s it. No YAML, no JSON schema. Just JavaScript and some rules that make sense.

The Dockerfile

FROM node:18 AS builder

ARG VITE_API_URL
ARG VITE_APP_VERSION
ARG VITE_APP_ENV

ENV VITE_API_URL=$VITE_API_URL
ENV VITE_APP_VERSION=$VITE_APP_VERSION
ENV VITE_APP_ENV=$VITE_APP_ENV

WORKDIR /app
COPY . .

RUN npm ci
RUN npx envguardr validate ./env.schema.js
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
Enter fullscreen mode Exit fullscreen mode

Validation happens before the build. If anything’s missing or wrong, it fails fast — as it should.

What changed

Since I added envguardr:

  • I haven’t shipped a broken build.
  • I don’t debug missing env vars in production anymore.
  • My CI logs finally tell me what’s wrong instead of silently succeeding.

No magic. Just boundaries.

For anyone who's ever dealt with process.env in Docker

This isn't another generic linter. It's a purpose-built CLI for one thing: making sure your environment is what your app actually needs.

You write a schema. You run envguardr. It validates your env. If something's wrong, it kills the build.

That's the whole point.

Try it

npm install --save-dev envguardr
npx envguardr validate ./env.schema.js
Enter fullscreen mode Exit fullscreen mode

I built envguardr to protect myself from careless builds. It just happens to work for other people too.

Top comments (2)

Collapse
 
xwero profile image
david duymelinck

My first reaction is why use Vite to create an .env file?
If you have environment variables why not use them directly?

I think it is best to stop using .env files altogether. They are a bigger distraction than a solution.
The only viable use case is when you can't change the environment variables on the server. But with the virtualization of the servers that is almost a thing of the past.
The only time I use .env files is when a project is hosted on a shared server.

Collapse
 
fontebasso profile image
Samuel Fontebasso

I completely agree. Using .env files often hides real issues and delays proper validation of critical settings. envguardr was built with that in mind. It doesn't load or check .env files. All validation runs directly against process.env at build time, ensuring only properly configured environments move forward in the pipeline.

I also have no plans to add support for .env files for the same reason.