Your Bolt.new app crashed after deploy — the environment variable gap nobody warns you about

Bolt.new apps that work perfectly in preview often crash the moment they're deployed, because environment variables set in Bolt's Secrets panel don't automatically transfer to Netlify or Vercel. Here's why, how to spot it, and the fix.

Your Bolt.new app ran fine in the preview. You hit deploy — to Netlify, to Vercel, wherever — and it’s just broken. A blank screen, a generic “Build failed” in the logs, or it builds fine and then crashes the moment it tries to talk to Supabase or Stripe. Nothing in the code changed between the working preview and the broken deploy.

If you’re staring at that gap, the cause is almost always the same thing: your environment variables never made it to production.

Why this happens

Bolt.new has its own Secrets panel where you set keys during development, and those secrets are scoped to Bolt’s own preview environment — they’re not the same thing as the .env file your deploy host reads, and they don’t get carried over automatically when you connect the project to Netlify or Vercel. The build runs on infrastructure that has no idea those secrets exist, so it starts up with undefined where a Supabase URL or a Stripe key should be. Most of the time the failure doesn’t even say which variable is missing — you just get a crash or a blank screen, because the app never got far enough to log a useful error.

It gets worse with Stripe specifically. Bolt tends to generate code without cleanly separating which key belongs where: a publishable key (VITE_STRIPE_PUBLISHABLE_KEY or similar) is meant to ship to the browser, but a secret key (STRIPE_SECRET_KEY) is not. Because the agent’s shortest path to “it works” in preview is just reading whatever’s in scope and using it, it’s easy to end up with a secret key referenced from client-side code — which works in preview and is a real exposure once it’s live.

Supabase adds its own version of the same gap: a webhook signing secret needs to live in Supabase’s own secrets store for an Edge Function to read it, not in a generic .env file. Bolt doesn’t reliably steer you toward that distinction, so a secret that’s “set” in the wrong place looks configured right up until the webhook that depends on it silently fails in production.

How to tell if this is your problem

  1. Open your browser console on the live deploy, not the Bolt preview. Errors referencing undefined API URLs, failed fetch calls to a service that clearly should be configured, or a client library throwing on initialization are the signature of a missing key rather than a code bug.
  2. Check your deploy host’s environment variable settings (Netlify: Site Settings → Environment Variables; Vercel: Project Settings → Environment Variables) against what’s actually set in Bolt’s Secrets panel. If Bolt has entries the host doesn’t, that’s the mismatch.
  3. Grep your own code for every import.meta.env / process.env reference and confirm each one has a matching entry on the host — not just in Bolt. It’s common to be missing one or two, not all of them, which is why the app half-works before it crashes.

The fix

Inventory everything the app actually reads. Don’t guess — ask Bolt directly: “List every environment variable this project requires to run in production, and where each value comes from.” Cross-reference that list against what’s already in Bolt’s Secrets panel.

Set each one on your actual deploy host, not just in Bolt. For Netlify, that’s Site Settings → Environment Variables → add each name/value pair, then trigger a fresh deploy (adding variables after the fact doesn’t retroactively fix a build that already ran). For Vercel, it’s the equivalent under Project Settings → Environment Variables. Names are case-sensitive on both — a variable named SUPABASE_URL in your code and supabase_url in the dashboard is two different variables as far as the host is concerned.

Separate public from secret, deliberately. Anything prefixed for client exposure (Vite’s VITE_ prefix, Next’s NEXT_PUBLIC_ prefix) is the only kind of key that should ever appear in code your browser downloads. If you find a secret key — Stripe’s secret key, a service-role Supabase key, anything without that prefix — referenced anywhere in frontend code, rotate it immediately and move the call it supports to a server-side function instead.

Put webhook and service secrets where the platform expects them, not in your general .env. A Supabase Edge Function reads from Supabase’s own secrets store; setting the same value in your deploy host’s environment variables won’t reach it.

Verify locally before you deploy again. Run the production build command in Bolt’s own terminal (npm run build) before pushing to your host. A failure there is faster to debug than a failure buried in your host’s build logs, and it catches missing-variable crashes before they cost you a deploy cycle.

How to avoid this next time

Treat “connect to Netlify/Vercel” and “copy every secret to the new host” as one step, not two — the deploy succeeding is not evidence the app will run. Before you call a Bolt project done, open the live URL in an incognito window and exercise every feature that touches an external service (auth, payments, database writes), not just the pages that render without one.

Comments