Skip to content

What Are Environment Variables, and Which Ones Do I Need in Production?

6 min read

An environment variable is a named setting your app reads at runtime instead of hard-coding, like DATABASE_URL or STRIPE_SECRET_KEY. The ones you need in production are every variable your code reads that isn't already committed to the repo, and the fastest way to find them is to search your code for where the app reads its config. Missing even one is the single most common reason a vibe-coded app works on your laptop and dies the moment it goes live.

Why this happens

Your app needs a handful of values that change depending on where it runs: the database it connects to, the API keys it uses, the URL it thinks it lives at. These don't live in your code, because some of them are secret and all of them differ between your laptop and production. Instead they live in a local file, usually .env or .env.local, that your app reads on startup.

That file is deliberately not committed to your repo. So when your AI agent set the app up, it created .env on your machine and everything worked. Then you deployed, the server had no .env, and the app either crashed on boot or threw 500 errors the instant it tried to read a value that wasn't there. The agent built exactly what you asked and never mentioned that this file has to be recreated, by hand, in production. You didn't ask, so it stayed silent.

How to check

You need the full list of variables your app expects. Two quick ways:

  1. Look for an example file. Many setups include .env.example or .env.sample, which lists every variable name with the values blanked out. That is your checklist.

  2. Search the code. From your project root, grep for how the app reads config. In a JavaScript or TypeScript project:

    grep -rho "process\.env\.[A-Z0-9_]*" src app | sort -u
    

    In Python, search for os.environ or os.getenv instead. Every unique name that comes back is a variable your app reads and therefore may need set in production.

  3. Compare against your real .env. Open the .env file on your machine. Anything in the grep list that isn't in your .env, or is blank, is a gap.

The fix

  1. Build the master list from the steps above. Write down every variable name and, from your local .env, what a real value looks like.

  2. Sort public from private. In Next.js and Vite, only variables with a NEXT_PUBLIC_ or VITE_ prefix are sent to the browser; everything else stays server-only. A secret key with a public prefix is a leak, and a browser-needed value without the prefix will read as undefined. Get the prefix right for each one.

  3. Set them in your host, not in a file. Production platforms have a settings screen for this. On Vercel it's Project Settings, Environment Variables. On Netlify it's Site configuration, Environment variables. On Railway or Render it's the Variables tab. Add each name and its production value there. Use the production database and live keys, not your local test ones.

  4. Redeploy, then verify. Most platforms only pick up new variables on the next deploy, so trigger one. Then load the live site and exercise the paths that touch each service: sign in, load data, hit checkout. A 500 on one of those usually means one variable is still missing or misspelled.

The trap to avoid

Do not commit your .env file to the repo to "make sure production has it." That puts every secret you own into Git history, where it is compromised the moment anyone sees it, and it still won't set the values on your host. Keep .env in .gitignore and set production values through the host's settings screen. If a secret has already gone into a commit, rotate it.

Where this fits

A missing environment variable is invisible until the exact moment a real user hits the feature that needs it, which is the worst possible time to find out. This is closely tied to why an app works locally but breaks in production and to where your API keys should actually live. The free Readiness Report checks your project for variables your code reads but production doesn't have set, before your first users do. If you want the whole list reconciled and set for you, that's part of the Finishing Pass.