Next.js Environment Variables Undefined in Production: Fix

process.env works locally but is undefined on Vercel? The 6 causes: NEXT_PUBLIC inlining, missing redeploy, wrong environment scope, dynamic keys, Edge runtime, and typos.

In Next.js, process.env.X is undefined in production because variables prefixed NEXT_PUBLIC_ are baked into the JavaScript at build time, server-only variables are not exposed to the browser, and changing a variable in your host does not affect an existing build until you redeploy.

Almost every case falls into one of six causes. Work through the list top to bottom.

Cause Checklist

# Cause Symptom Fix
1 Missing NEXT_PUBLIC_ prefix on a client-side value undefined in browser, fine in API route Rename, or fetch it via a server route
2 Variable added after the build Still old or empty value Redeploy (rebuild)
3 Wrong environment scope Works in Preview, undefined in Production Enable Production scope on the variable
4 Dynamic lookup process.env[name] Undefined only in browser Reference each variable literally
5 .env.local never uploaded Works only on your laptop Add to host dashboard or CI secrets
6 Typo or trailing whitespace Auth or API calls fail oddly Re-paste value, check the key name

1. Browser vs Server Variables

Only variables starting with NEXT_PUBLIC_ are available in client components. Everything else is server-only, which is the correct and secure default.

// Works on server, undefined in the browser
const secret = process.env.STRIPE_SECRET_KEY

// Works everywhere, but is public. Never put secrets here.
const pk = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY

If the browser needs a server secret's result, call an API route or Server Action. Do not rename a secret to NEXT_PUBLIC_ to make the error go away. That publishes it to every visitor.

2. Build-Time Inlining Surprises People

NEXT_PUBLIC_* values are replaced with literal strings during next build. Updating the variable in Vercel and refreshing the page does nothing. You need a new deployment. This also means you cannot build once and promote the same artifact across staging and production with different public values.

3. Dynamic Keys Are Not Inlined

// Broken in client code: Next.js cannot find the key at build time
const key = 'NEXT_PUBLIC_API_URL'
const url = process.env[key]

// Works
const url = process.env.NEXT_PUBLIC_API_URL

Destructuring (const { NEXT_PUBLIC_API_URL } = process.env) has the same problem in client bundles.

4. Edge Runtime and Middleware

Middleware and Edge routes only see variables available in that runtime and cannot use Node-only APIs. If an env var works in your API route but not in middleware, see Vercel Edge Runtime errors.

Stop This Bug From Recurring: Validate at Startup

Fail the build, loudly, instead of failing in front of a customer at 2 a.m.

// env.ts
import { z } from 'zod'

const schema = z.object({
  DATABASE_URL: z.string().url(),
  STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
  NEXT_PUBLIC_APP_URL: z.string().url(),
})

export const env = schema.parse(process.env)

Import env instead of touching process.env directly. A missing variable now throws at boot with a clear message. The same schema approach protects request bodies; see the Zod validation guide.

How Missing Env Vars Hurt in Production

A missing database URL looks like a connection failure. A missing webhook secret looks like random signature errors; compare with Stripe webhook failures. The symptom rarely names the variable, which is why they waste hours.

Let Relia Explain the Error

Relia learns what is normal for your app and tells you when a new error pattern appears. When a release starts throwing Invalid URL or Cannot read properties of undefined, it writes the incident up in plain words: what happened, why it thinks so (with a confidence level), and one thing to do next. On request it writes a fix plan, such as adding a validation schema for your environment variables, with a "Copy for your AI assistant" button; Relia doesn't change code itself, and after you ship it checks the fix against live traffic.

FAQ

Why is process.env.NEXT_PUBLIC_X undefined in production? It was either not set when the build ran, not enabled for the Production environment, or accessed with a dynamic key. Set it, then redeploy.

Do I need to redeploy after changing an env var?

Yes. Server variables are read from the new deployment, and public variables are compiled into the build.

Is it safe to expose keys with NEXT_PUBLIC_? Only values meant to be public, such as publishable keys and site URLs. Never expose secrets, tokens, or database credentials.

All guides