Blog
3 min read

Why Is My Environment Variable Undefined? (Vite, Next.js, Node)

Your .env file has the value but the code sees undefined. The reasons are almost always the same: the wrong prefix (VITE_, NEXT_PUBLIC_), the wrong file name or folder, not restarting the dev server, build-time vs runtime, or the variable never being set in production.

console.log(process.env.API_URL)        // undefined
console.log(import.meta.env.API_URL)    // undefined

The value is right there in your .env file, so why can't the code see it? It's one of the most common beginner problems, and there are only a handful of causes. Work through them in order.

(New to this? Environment variables explained covers the basics.)

1. You didn't restart the dev server

.env files are read when the server starts. Change the file → stop the dev server (Ctrl+C) → start it again. Hot reload doesn't pick up .env changes in most setups.

2. Frontend code needs a special prefix

Browser code can't see your environment variables unless you explicitly expose them, because anything sent to the browser is public. Each framework uses a prefix as the "yes, I mean to make this public" switch:

Framework Prefix Read with
Vite (React, Vue, Svelte) VITE_ import.meta.env.VITE_API_URL
Next.js (client components) NEXT_PUBLIC_ process.env.NEXT_PUBLIC_API_URL
Create React App (legacy) REACT_APP_ process.env.REACT_APP_API_URL
Astro PUBLIC_ import.meta.env.PUBLIC_API_URL

So API_URL=... won't work in browser code; VITE_API_URL=... will.

Important: the prefix makes the value public. Never put a secret key behind VITE_ or NEXT_PUBLIC_ — anyone can read it in the browser. Secrets belong in server code only. (Keep API keys out of an AI-built app)

3. Wrong syntax for the tool

  • Vite uses import.meta.env, not process.env.
  • Plain Node.js does not read .env files on its own. Either load it:
node --env-file=.env server.js

(built into modern Node), or use the dotenv package at the very top of your entry file.

  • In Next.js, read the variable directly as process.env.NEXT_PUBLIC_X. Dynamic access like process.env[name] isn't replaced at build time in client code.

4. Wrong file name or location

  • The file must be in the project root (next to package.json), not in src/.
  • Exact name: .env, .env.local, .env.development. Not env, .env.txt (Windows can hide that .txt), or .ENV.
  • In a monorepo, the .env must be in the app's own folder, or loaded explicitly.

5. Formatting in the .env file

API_URL=https://api.example.com     ✅
API_URL = https://api.example.com   ⚠️ spaces can break some loaders
export API_URL=...                  ⚠️ works in some loaders, not others
API_URL="value with spaces"         ✅ quote values with spaces or #

6. It works locally but is undefined in production

Your .env file isn't deployed (it's in .gitignore, as it should be — what is .gitignore?). You must set the variables in your host's dashboard or server config too.

And for frontend variables there's an extra twist: they're baked in at build time. Vite and Next.js replace import.meta.env.VITE_X with the literal value when you run the build. So:

  • The variable must be set when the build runs, not just when the app starts.
  • After changing it, you must rebuild and redeploy — restarting isn't enough.

Server-side variables (read in API routes or server code) are read at runtime, so a restart is enough for those.

(Why your app works locally but not in production covers more of these gaps.)

Quick checklist

  1. Restarted the dev server?
  2. Using the right prefix for browser code?
  3. import.meta.env for Vite, process.env for Node/Next?
  4. File named exactly .env, in the project root?
  5. Set in production, and was it set at build time?

The summary

  • Restart after editing .env.
  • Browser code needs VITE_ / NEXT_PUBLIC_ — and those values are public.
  • Node needs --env-file or dotenv to read .env at all.
  • Frontend variables are fixed at build time: set them before building, rebuild after changing.

EasySpawn keeps your environment variables on the server, available to builds and to the running app alike, so development and production read the same settings. See how it works or join the waitlist.

Related: Environment Variables Explained · How to Keep API Keys Out of an AI-Built App · Secrets Management Beyond .env Files · What Is Vite?

Keep reading