afterbuild/ops
ERR-441/Vercel · env
ERR-441
TypeError: Cannot read properties of undefined (reading 'key')

appears when:After deploying to Vercel when the code compiles fine but process.env.X returns undefined at runtime

env variables not loading Vercel

Vercel has three env scopes (Production, Preview, Development) and NEXT_PUBLIC_ values bake into the bundle at build time. Four causes account for every undefined.

Last updated 17 April 2026 · 5 min read · By Hyder Shah
Direct answer
env variables not loading Vercel is almost always the wrong scope, a missing NEXT_PUBLIC_ prefix on a client-side variable, or no redeploy since the change. Set it in all three scopes (Production, Preview, Development), add NEXT_PUBLIC_ only for client-readable values, and trigger a fresh deployment so NEXT_PUBLIC_ values bake into the new bundle.

Quick fix for env variables not loading

lib/env.ts
typescript
01// lib/env.ts — validate env vars at boot with zod02import { z } from "zod";03 04const envSchema = z.object({05  // Server-only (no NEXT_PUBLIC_ prefix)06  DATABASE_URL: z.string().url(),07  STRIPE_SECRET_KEY: z.string().startsWith("sk_"),08 09  // Client-readable (NEXT_PUBLIC_ prefix required)10  NEXT_PUBLIC_SUPABASE_URL: z.string().url(),11  NEXT_PUBLIC_SUPABASE_ANON_KEY: z.string().min(1),12  NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().startsWith("pk_"),13});14 15export const env = envSchema.parse(process.env);16// Now the build fails loudly if any var is missing
Add a zod schema on process.env — the build fails loudly when a var is missing

Deeper fixes when the quick fix fails

01 · Pull remote env vars locally to confirm they exist

terminal
bash
01# Syncs the Production values into a local .env.local02vercel env pull03 04# Verify the expected key is present05grep STRIPE_WEBHOOK_SECRET .env.local

02 · Rename a client-side variable to include NEXT_PUBLIC_

components/checkout.tsx
typescript
01// ❌ undefined in the client bundle02const pk = process.env.STRIPE_PUBLISHABLE_KEY;03 04// ✅ inlined at build time, visible in the browser bundle05const pk = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY;
Also rename the variable in the Vercel dashboard — both names must match

03 · Force a fresh deploy with an empty commit

terminal
bash
01git commit --allow-empty -m "redeploy to pick up env changes"02git push

Why AI-built apps hit env variables not loading

Lovable, Bolt, Replit, and Cursor put secrets in .env.local during development — the local convention for every Node.js framework. .env.local is in .gitignore by default. Nothing ever uploads it to Vercel. At deploy, the build succeeds because Next.js only reads real env vars at runtime — absence is not a compile error, just an undefined. The first page that reads the key 500s with Cannot read properties of undefined.

The second pattern is the NEXT_PUBLIC_ prefix. AI-generated code uses process.env.STRIPE_PUBLISHABLE_KEY in a client component without the prefix. On the server the variable resolves; in the client bundle it was stripped at build time because Next.js inlines only NEXT_PUBLIC_-prefixed names. Local dev conflates server and client env aggressively — the bug is invisible until production.

The third structural cause is environment scope drift. Vercel has three independent scopes: Production, Preview, Development. Every variable has three checkboxes. Founders add a variable on a preview branch, check only Preview, and it never reaches Production. When main deploys, the variable returns undefined. Tick all three unless there is a specific reason to differ.

env variables not loading by AI builder

How often each AI builder ships this error and the pattern that produces it.

AI builder × env variables not loading
BuilderFrequencyPattern
LovableEvery Supabase scaffoldWrites only to .env.local, never copies to Vercel
Bolt.newCommonTicks only Preview scope, misses Production
v0CommonUses process.env.STRIPE_PUBLISHABLE_KEY in client — missing prefix
CursorSometimesHard-codes secrets rather than reading from env
Replit AgentCommonSets vars but never redeploys; NEXT_PUBLIC_ stale in bundle

Related errors we fix

Stop env variables not loading recurring in AI-built apps

Still stuck with env variables not loading?

Emergency triage · $299 · 48h turnaround
We restore service and write the root-cause report.
start the triage →

env variables not loading questions

Why is process.env.MY_KEY undefined in Vercel production?+
Four common causes. Variable set to Preview scope only, not Production. Variable added after the last deploy and no redeploy has run. Variable used in a client component without the NEXT_PUBLIC_ prefix. Variable is in .env.local locally and was never added to Vercel dashboard. Fix one at a time.
What does NEXT_PUBLIC_ actually do?+
Next.js replaces any occurrence of process.env.NEXT_PUBLIC_X in code with the literal value at build time. Without the prefix, the variable is only available on the server. Client components that reference NEXT_PUBLIC_ names read them from the compiled bundle. Security boundary: names without the prefix never leave the server. Renaming a secret to NEXT_PUBLIC_ is how private keys end up in public bundles.
Do I need to redeploy after adding an env var?+
Yes. Vercel injects env vars at build and runtime, but NEXT_PUBLIC_ values are inlined during the build. Changing a NEXT_PUBLIC_ var without redeploying leaves the old value in the bundle indefinitely. Server-side variables reload on next cold start. Rule: after any env change, trigger a redeploy with an empty commit or the Vercel redeploy button.
Why does my env var work locally but not on Vercel?+
.env.local is not deployed. Vercel reads env vars from its own dashboard, not from files in the repo. `vercel env pull` syncs them down for local use, but the dashboard is source of truth. Also check the target environment dropdown — Production, Preview, and Development are three separate scopes with three separate values.
How long does this take to fix?+
Five minutes if you have Vercel dashboard access. Two minutes to identify the wrong variable, two minutes to set it in the correct scope, one minute to redeploy. Emergency Triage at $299 covers it in 48 hours if Vercel access is shared across a team and nobody is sure who owns what.
Next step

Ship the fix. Keep the fix.

Emergency Triage restores service in 48 hours. Break the Fix Loop rebuilds CI so this error cannot ship again.

About the author

Hyder Shah leads Afterbuild Labs, shipping production rescues for apps built in Lovable, Bolt.new, Cursor, Replit, v0, and Base44. our rescue methodology.

Sources