Back to Tools

process.env is undefined — How to Fix Node.js Environment Variables

6 proven fixes covering Node.js, Next.js, Vite, and deployment platforms

process.env.MY_VAR returning undefined is one of the most frustrating Node.js issues — because the fix depends entirely on where and how your code runs. This guide covers every scenario.

The Most Common Cause

Environment variables in Node.js are not loaded automatically from a .env file. The OS only exposes variables that are explicitly set in the shell environment. The dotenv package bridges this gap — but only if it runs before any of your other code.

Common mistake — dotenv called too late:

import { connectDB } from './db'; // ← runs BEFORE dotenv!
require('dotenv').config();       // too late — DB already used undefined env vars

console.log(process.env.DB_URL); // undefined

Fix 1: Load dotenv BEFORE Everything Else

require('dotenv').config() must be the very first line in your entry point file — before any other imports or requires.

Broken:

const express = require('express');
require('dotenv').config(); // ❌ too late

const app = express();
console.log(process.env.PORT); // undefined

Fixed:

require('dotenv').config(); // ✅ line 1 — before anything else

const express = require('express');
const app = express();
console.log(process.env.PORT); // "3000"

Fix 2: .env File Location

By default, dotenv looks for .env relative to the directory where you run node — which is usually the project root. If your .env is inside src/, dotenv will silently fail to find it.

Wrong structure:

my-project/
├── src/
│   ├── .env        ❌ dotenv won't find this
│   └── index.js
└── package.json

Correct structure:

my-project/
├── .env            ✅ in the project root
├── src/
│   └── index.js
└── package.json

Fix 3: Next.js — NEXT_PUBLIC_ Prefix Required for Client-Side

Next.js has two environments: the server (Node.js) and the browser. Variables without the NEXT_PUBLIC_ prefix are only available server-side. Accessing them in a client component returns undefined.

Broken — accessing server-only var in browser:

// .env
API_URL=https://api.example.com

// components/MyComponent.tsx (client component)
'use client';
console.log(process.env.API_URL); // ❌ undefined in browser

Fixed — use NEXT_PUBLIC_ prefix:

// .env
NEXT_PUBLIC_API_URL=https://api.example.com

// components/MyComponent.tsx (client component)
'use client';
console.log(process.env.NEXT_PUBLIC_API_URL); // ✅ "https://api.example.com"

Server components and API routes can access any variable without the prefix.

Fix 4: Vite — Use import.meta.env and VITE_ Prefix

Vite does not polyfill process.env. You must use import.meta.env and all custom variables must be prefixed with VITE_.

Broken in Vite:

// .env
API_URL=https://api.example.com

// src/main.js
console.log(process.env.API_URL); // ❌ undefined — wrong API

Fixed in Vite:

// .env
VITE_API_URL=https://api.example.com

// src/main.js
console.log(import.meta.env.VITE_API_URL); // ✅ "https://api.example.com"
console.log(import.meta.env.MODE);          // "development" or "production"

Fix 5: Vercel / Deployment — Variables Set in Dashboard, Not .env

Vercel, Netlify, Railway, and similar platforms do not read your .env file. You must configure environment variables through their dashboards.

Common mistake:

# .env committed to repo or assumed to be deployed
DATABASE_URL=postgres://...  # ❌ Vercel ignores this file

Correct approach:

# 1. Add to Vercel dashboard:
#    Project Settings → Environment Variables
#    Key: DATABASE_URL
#    Value: postgres://user:pass@host/db
#    Environment: Production, Preview, Development

# 2. Your code works identically:
const db = process.env.DATABASE_URL; // ✅ works in production

The .env file should be in your .gitignore — never commit secrets to version control.

Fix 6: Variable Name Typo — Console.log All Env Vars to Debug

A simple typo in the variable name is surprisingly common. Use this debug snippet to print all loaded environment variables and verify the exact names.

Debug snippet — print all env vars:

require('dotenv').config();

// Print all env vars loaded from .env (safe for local debugging only)
console.log('Loaded env vars:', Object.keys(process.env).filter(k =>
  !['PATH', 'HOME', 'USER', 'SHELL'].includes(k) // filter system vars
));

// Or check a specific variable with a fallback message:
const apiKey = process.env.API_KEY;
if (!apiKey) {
  throw new Error('API_KEY is not set. Check your .env file.');
}

Quick Debug Checklist

  1. Is require('dotenv').config() the very first line?
  2. Is the .env file in the project root (same level as package.json)?
  3. Is dotenv installed? Run npm list dotenv to verify.
  4. In Next.js — does the variable need the NEXT_PUBLIC_ prefix?
  5. In Vite — are you using import.meta.env.VITE_*?
  6. On Vercel/Netlify — are the variables set in the dashboard?
  7. Is there a typo in the variable name (check case sensitivity)?
  8. Did you restart the dev server after editing the .env file?

Use our free JSON Formatter to inspect your config files →

Paste your JSON config and format it instantly — no signup required.

Frequently Asked Questions

Why is process.env.MY_VAR undefined in Node.js?

The variable is not set in your shell environment and dotenv has not loaded your .env file. Ensure require('dotenv').config() is the first line of your entry file.

Why is process.env undefined in Next.js client components?

Only variables prefixed with NEXT_PUBLIC_ are bundled into client-side code. Without the prefix, the variable stays server-only and returns undefined in the browser.

Why does it work locally but not on Vercel?

Vercel does not use your .env file. Go to your project's Settings > Environment Variables in the Vercel dashboard and add each variable there.

How do I use environment variables in Vite?

Vite exposes variables via import.meta.env instead of process.env. Your variables must start with VITE_.

Does dotenv work with ES modules?

Yes — use import 'dotenv/config' as your first import, or pass --require dotenv/config to the node command.

Related Tools