"Invalid API key" or Undefined Env Vars on Vercel: How to Fix It
Quick answer: Your app works locally but on Vercel you get "Invalid API key" or undefined environment variables? Here's how Vercel env vars work and how to fix them.
The error
Common variants:
Error: supabaseUrl is required.
AuthApiError: Invalid API key
OpenAI API error: 401 Incorrect API key provided: undefined
Or process.env.MY_KEY is simply undefined in production.
Why it happens
.env.localis not deployed (it's git-ignored, as it should be). Vercel needs its own copy.- The variable was added after the last deployment. Env vars apply only to new deployments.
- It was added for the wrong environment (Production vs Preview vs Development).
- It's used in browser code without the
NEXT_PUBLIC_prefix (Next.js) orVITE_prefix (Vite). - Typos, quotes, or trailing spaces/newlines pasted into the value.
Fixes
1. Add the variables in Vercel
Vercel → Project → Settings → Environment Variables. Add each key, tick the environments that need it, then redeploy (Deployments → ⋯ → Redeploy). Or use the CLI:
vercel env add NEXT_PUBLIC_SUPABASE_URL production
vercel env pull .env.local # pulls the Development values (add --environment=production for prod)
2. Use the right prefix for browser code
// Next.js: inlined at BUILD time, visible in the browser
const url = process.env.NEXT_PUBLIC_SUPABASE_URL!;
// Vite
const url = import.meta.env.VITE_SUPABASE_URL;
Public prefixes are baked in at build time, which is another reason a redeploy is required.
3. Keep secrets server-side
Secret keys (SUPABASE_SERVICE_ROLE_KEY, OPENAI_API_KEY, STRIPE_SECRET_KEY) must not get a public prefix. Anything with NEXT_PUBLIC_ or VITE_ ends up in the JavaScript sent to every visitor. Use secrets only in Route Handlers, Server Actions, or API routes:
// app/api/chat/route.ts
export async function POST(req: Request) {
const key = process.env.OPENAI_API_KEY; // server only
// ...
}
4. Fail fast with a clear message
function requireEnv(name: string) {
const v = process.env[name];
if (!v) throw new Error(`Missing env var: ${name}`);
return v;
}
Note: for NEXT_PUBLIC_ variables in client code, reference them literally (process.env.NEXT_PUBLIC_X). Dynamic lookups like process.env[name] aren't inlined in the browser.
5. Check the value itself
Re-copy the key from the provider dashboard. Remove quotes and trailing spaces. Make sure it's the key for the right project (e.g. the Supabase anon or sb_publishable_… key for the client, never the service role or sb_secret_… key).
FAQ
I added it but it's still undefined. Did you redeploy? Is it ticked for Production? Is the Supabase anon key safe to expose? It's designed to be public, but only if Row Level Security is enabled on your tables.
Still stuck? Paste your exact error into the free Error Fixer to get a plain-English cause, the fix, and a prompt to paste back into your AI tool.