MELLEPRISE MELLEPRISE MP Blog
← All articles

Vercel env vars never reached production after you published

Pastel comic of a suitcase of labelled bottles left on a desk while a plane takes off

Your vercel env vars worked on localhost, then production crashed on the first API call because process.env was empty.

Local dev felt complete. Supabase connected. Stripe charged the test card. Login redirected correctly. You pushed to GitHub, Vercel built green, and the live URL loaded a shell. Click sign in and nothing happens. Server routes return 500. The browser console shows missing keys. The app on your laptop and the app on *.vercel.app are not the same binary. They read from different environment sources.

Vercel does not read the .env file from your repo unless you committed it, which you should not. Production builds use variables you define in the Vercel project settings or inject through the CLI. Lovable can set keys for preview inside the editor. That wiring stops at publish unless you copy every name and value to Vercel Production and redeploy.

Env never left the laptop

This is the root cause behind half of “works locally, broken live” reports. You created .env.local while following a tutorial. Next.js or Vite loaded it automatically. The AI assistant referenced those names in code: VITE_SUPABASE_URL, STRIPE_SECRET_KEY, OPENAI_API_KEY. Git push excluded the file via .gitignore. Correct for security. Vercel never received the values.

What you see on the live URL:

  • undefined in server logs for env names that exist locally
  • Client bundles with empty strings where keys should be
  • Supabase client initialized with undefined URL
  • Stripe webhook verification failing because STRIPE_WEBHOOK_SECRET is missing
  • OAuth or magic links breaking because redirect helpers read unset vars

Open Vercel β†’ your project β†’ Settings β†’ Environment Variables. Search for each name your code references. If the list is empty or only shows Preview and Development, production builds have nothing to inject. Your secrets never left the laptop.

Lovable users hit the same gap from a different angle. The editor stores integration keys for preview. Connecting GitHub and Vercel deploys the code, not the Lovable secret drawer. You must transcribe names and values manually or use the Vercel CLI.

Production vs local

Vercel exposes three environments: Production, Preview, and Development. Each can hold different values for the same key. A common mistake is adding vars only to Preview because that is where you tested pull requests. Production deploys from main and still lacks keys.

Local .env files also split by convention. Next.js reads .env.local for all modes on your machine. .env.production on disk does not automatically sync to Vercel. The hosting dashboard is the source of truth for cloud builds.

Framework rules differ. Vite exposes only VITE_-prefixed names to the browser bundle. Server-only secrets without that prefix stay on the server in Next.js API routes but still must exist in Vercel for production. Putting a secret in client code because it worked in a rushed preview leaks it in the bundle. Putting it only in .env.local without adding it to Vercel leaves production blind.

Compare side by side:

  • Local: reads .env, .env.local, shell exports; hot reload picks up changes
  • Vercel Production: reads dashboard vars for Production scope at build time and runtime for serverless functions
  • Vercel Preview: PR deployments; can use Preview-scoped vars, not Production unless you duplicate keys
  • Lovable preview: editor-injected keys; separate from Vercel unless you copied them

After any change, trigger a fresh production deployment. Vercel bakes client env at build time. Editing a variable without redeploying leaves the old bundle on the CDN.

Why AI builds assume your .env exists everywhere

Coding agents generate process.env.NEXT_PUBLIC_SUPABASE_URL and move on. They see your local file when you run dev. They cannot see the Vercel dashboard. Generated README files say “add to .env” without a second line for production hosting.

Lovable chat optimizes for preview green. It connects Supabase and Stripe inside the product. Publish hands off to Git and Vercel. That handoff does not include a checklist of env names unless you build one. The model treats environment wiring as done when the integration card shows connected.

Stripe webhooks are a frequent casualty. Local dev used the Stripe CLI to forward events to localhost. Production needs a live endpoint URL and STRIPE_WEBHOOK_SECRET from the live webhook object. The secret in your local CLI session never applies to Vercel. Payments succeed in the Stripe dashboard while your app database stays empty.

Set vercel env vars the right way

Work from your code, not from memory. Missing one key fails the whole flow.

  1. Grep the repo for process.env and import.meta.env. List every name.
  2. Open Vercel β†’ Settings β†’ Environment Variables.
  3. Add each name with the correct value. Enable Production. Add Preview too if PR deploys need the same keys.
  4. Match Lovable or Supabase dashboard values for production projects, not dev projects.
  5. For Next.js public names, use NEXT_PUBLIC_ prefix. For Vite client names, use VITE_ prefix.
  6. Save, then Deployments β†’ Redeploy latest production without cache.
  7. Open the live URL, DevTools β†’ Sources or Network, and confirm client bundles no longer show empty config.
  8. Hit a server route or API function and confirm logs show defined env values (never log full secrets).

CLI alternative for teams:

vercel env add VITE_SUPABASE_URL production
vercel env pull .env.vercel.production

Commit .env.example with names only. Never commit real values. Document which vars are client-exposed vs server-only so the next deploy is not a guessing game.

Auth often breaks in the same deploy window because redirect URLs depend on the live origin while Supabase keys were missing. After env vars are set, confirm Site URL and Redirect URLs match your Vercel domain. See lovable login for callback fixes.

Env vars are one of five production settings AI editors rarely prompt for. Webhooks, RLS, auth URLs, and TLS fail on the same launch weekend. The lovable deploy checklist covers the full set so you are not fixing undefined keys while login and payments are also miswired.

Pre-launch checklist

  • Every process.env and import.meta.env name exists in Vercel Production
  • Production checkbox enabled, not only Preview or Development
  • Client-exposed keys use the correct public prefix for your framework
  • Server secrets never use client prefixes and never ship in the browser bundle
  • Values match the live Supabase, Stripe, and OAuth projects, not local dev projects
  • Redeploy completed after the last env change
  • .env.example in the repo lists required names without secret values

Local .env proves the code can work. Vercel Production env proves the code works for users.

FAQ

Why do vercel env vars work locally but not in production?

Next.js and Vite read .env from your machine during local dev. Vercel production builds use only variables you set in the Vercel dashboard or CLI for the Production environment. A .env file that never left your laptop is invisible to the deploy.

Where do I add vercel env vars for a Lovable app?

Open your Vercel project, go to Settings, then Environment Variables. Add each key with the Production checkbox enabled. Redeploy after saving. Lovable preview keys do not copy themselves when you connect GitHub.

Do I need to redeploy after changing vercel env vars?

Yes. Existing deployments baked the old values into the build output. Update the variable in Vercel, then trigger a new production deployment so server and client bundles pick up the new secrets.