VibeFix › Guides

Environment variable undefined after deploy? Fix VITE_, NEXT_PUBLIC_ and missing env vars on Vercel and Netlify

Your app works on localhost, but the deployed version shows a blank page, "supabaseUrl is required." in the console, or API calls going to undefined/api/…. Usually an environment variable that exists on your machine doesn't exist in the build on Vercel or Netlify, or exists but the browser can't see it. This guide covers the three causes we see in almost every Lovable, Bolt and Cursor app: the variable was never added to the host, it has the wrong prefix, or the site wasn't redeployed after adding it.

Updated October 22, 2026 · About 8 minutes to read

1. Confirm it's really a missing env var

Open the live site, then DevTools → Console. These messages almost always mean a variable is undefined in the deployed build:

Uncaught Error: supabaseUrl is required.
Error: supabaseKey is required.
Invalid supabaseUrl: Must be a valid HTTP or HTTPS URL.
Neither apiKey nor config.authenticator provided      // Stripe SDK
ReferenceError: process is not defined                 // process.env in a Vite app
GET https://yourapp.com/undefined/api/items 404        // API base URL missing

A blank white page with one of these errors means the app crashed while creating a client at startup (Supabase, Stripe, Firebase, OpenAI). Check the host's build log too: Next.js and server code may fail during the build instead.

To check what the browser actually received without leaking anything, open DevTools → Sources, press Ctrl/Cmd+Shift+F and search the bundled JS for a piece of the value you expect (for example your Supabase project ref abcd1234.supabase.co). If it isn't there, the value was never baked into the build. Locally, npm run build and then grep -r "abcd1234" dist/ (Vite) or .next/static (Next.js) does the same check.

2. Know when and where the variable is read

Most "it's set but still undefined" confusion comes from mixing up two different kinds of variables:

So first decide: is the failing code running in the browser (a React component, a supabase client file in src/) or on the server (an api/ folder, route.ts, a function)? The fix is different for each.

3. Use the right prefix and syntax for your framework

Bundlers only expose variables with a public prefix to browser code. Without it, the variable is deliberately left out and reads as undefined:

# .env (Vite)
VITE_SUPABASE_URL=https://abcd1234.supabase.co
VITE_SUPABASE_ANON_KEY=eyJ...            # publishable / anon key only

// src/lib/supabase.ts
const url = import.meta.env.VITE_SUPABASE_URL
const key = import.meta.env.VITE_SUPABASE_ANON_KEY
if (!url || !key) throw new Error('Missing VITE_SUPABASE_URL or VITE_SUPABASE_ANON_KEY')

That explicit check turns a vague blank page into an error that names the missing variable. The name in your code, your .env file and the host dashboard must match exactly, including case: VITE_SUPABASE_ANON_KEY and VITE_SUPABASE_KEY are different variables.

4. Add the variables on Vercel or Netlify (your .env file isn't deployed)

Your .env / .env.local file is normally in .gitignore, so it never reaches GitHub and never reaches the host. That's the single most common reason an app "works locally but not in production". Add every variable on the host:

Paste values exactly: no surrounding quotes, no trailing spaces or line breaks. In a dashboard the quotes become part of the value, so "https://abcd1234.supabase.co" fails as an invalid URL. On Vercel, values saved as Secret can't be read back after saving, so if you're unsure what you pasted, re-enter it.

5. Redeploy after every env var change

Vercel's docs are explicit: environment variable changes are not applied to previous deployments, only to new ones, so you must redeploy. The same is true on Netlify. Adding the variable and refreshing the live site changes nothing, because the old build still contains undefined.

Then hard-refresh the live site (Ctrl/Cmd+Shift+R) and repeat the Sources search from step 1. Browser variables are frozen into each build, so if you build once and promote the same build or Docker image to another environment, it keeps the values from the original build.

6. Next.js: when NEXT_PUBLIC_ is set but still undefined

Next.js only inlines NEXT_PUBLIC_ variables when the code reads them directly as process.env.NEXT_PUBLIC_NAME. Its docs list dynamic lookups that are not inlined, and AI-written config helpers love them:

// ✅ inlined at build time
const url = process.env.NEXT_PUBLIC_SUPABASE_URL

// ❌ NOT inlined: undefined in the browser
const name = 'NEXT_PUBLIC_SUPABASE_URL'
const url = process.env[name]

const env = process.env
const url = env.NEXT_PUBLIC_SUPABASE_URL

7. Vite: config, modes and string values

8. Keep secrets on the server (and don't 'fix' it by making them public)

The tempting fix for an undefined STRIPE_SECRET_KEY or OPENAI_API_KEY in a React component is to rename it VITE_… or NEXT_PUBLIC_…. Don't. Anything with a public prefix is pasted into JavaScript that every visitor downloads. Vite's docs warn that VITE_* variables should not contain sensitive information.

9. Lovable, Bolt and Cursor: find every variable the app needs

AI builders often set variables in their own preview environment that never make it into your export. Before deploying anywhere else, list every variable the code reads:

grep -rn "import.meta.env\|process.env\|Deno.env" src app pages lib supabase/functions 2>/dev/null

A prompt that works: "List every environment variable this app reads, whether each is used in the browser or on the server, and the exact name it needs on Vercel. Rename any browser variable to use the VITE_ prefix, move any secret key out of client code into a server function, and add a startup check for missing variables."

Still broken after a redeploy? Send us your live URL and the console error through the free check form or by email to fix@getvibefix.com. We'll tell you exactly what's wrong for free, before you pay anything.

FAQ

Why is my environment variable undefined on Vercel when it works locally?
Usually one of three things: the variable is only in your local .env file (which is gitignored and never deployed), it isn't enabled for the Production environment in Vercel's Settings → Environment Variables, or you added it without redeploying. Browser code also needs the VITE_ (Vite) or NEXT_PUBLIC_ (Next.js) prefix.

Do I need to redeploy after changing environment variables on Vercel or Netlify?
Yes. Vercel applies environment variable changes only to new deployments, and Netlify likewise uses them on the next build. Browser variables are baked into the JavaScript at build time, so redeploy and hard-refresh before testing.

Why is import.meta.env.VITE_SOMETHING undefined?
Check that the name starts with VITE_ (or your custom envPrefix), that it is set on the host for the build that is live, that the site was redeployed after adding it, and that you read it with the full static name import.meta.env.VITE_SOMETHING. Use import.meta.env, not process.env, in Vite client code.

Why is process.env.NEXT_PUBLIC_ variable undefined in the browser?
It wasn't present when next build ran (add it on the host and redeploy), the name is missing the NEXT_PUBLIC_ prefix, or the code reads it dynamically, e.g. process.env[name] or via a destructured copy of process.env. Next.js only inlines direct process.env.NEXT_PUBLIC_NAME references.

Is it safe to put an API key in a VITE_ or NEXT_PUBLIC_ variable?
Only if it's designed to be public, like the Supabase anon/publishable key or a Stripe publishable key. Prefixed variables are bundled into code every visitor can read. Secret keys (Stripe secret, OpenAI, Supabase service role) must stay in server code, functions or Edge Function secrets, and should be rotated if they were ever exposed.

Still stuck? We'll fix it at a flat price.

VibeFix fixes broken Lovable, Bolt, Cursor, Replit and v0 apps. Request a free check first, and we'll tell you what's wrong and which plan fits before you pay. If we can't fix it, you get a full refund.

Get a free check See pricing

Already know you need help? Quick Fix, $49 (one bug, 24h) · Standard Rescue, $129 · Deploy-Ready, from $199

Get 3 fixes for common vibe-coding bugs each week

One short, free email a week with 3 real fixes for Lovable, Bolt, Cursor, Replit and v0 apps.

By signing up, you agree to get one weekly email from VibeFix at this address. Unsubscribe anytime with the link in every email. We never sell or share your email.