Bolt app broke in production? A calm, step-by-step recovery.
It worked perfectly in the Bolt preview, then went live and broke — a blank page, a failed build, or features that just don't respond. Here's an ordered checklist to find which of the usual causes is breaking your live site, and the exact fix for each.
If it works in preview but not live, your production environment variables are missing or unprefixed (#2) — the #1 cause. A blank white screen is a runtime error or SPA-routing 404 (#3). A failed build on the host is usually a Node version or case-sensitive import (#4). Broken features are API/CORS/key issues (#5) or Supabase config (#7). If an AI edit caused it, roll back to the last working deploy first (#6), then diagnose calmly.
First, triage: find out which kind of broken it is
Don't change code yet. Spend two minutes deciding which of three failures you have — the fix is completely different for each.
- Build failed → your host (Netlify, Vercel, Cloudflare Pages, etc.) never produced a new site. Open the deploy/build log on the host and read the last red lines. Go to #4.
- Build succeeded but the page is blank or errors → the site deployed, but something fails in the browser. Open the live site, right-click → Inspect → Console, and reload. A red error there is your lead. Go to #2 and #3.
- Page loads, but a feature fails (login, save, data won't load) → the front-end is fine; a request to your API or database is failing. In the console, open the Network tab, trigger the feature, and look for the red/failed request. Go to #5 and #7.
1. Open the deploy log and the browser console
Your host keeps a log of every deploy. On Netlify it's Deploys → the latest deploy → Deploy log; on Vercel it's the deployment → Building / Runtime Logs. A failed build ends with a clear error and a non-zero exit code. A green "Published" with a broken site means the problem is in the browser, not the build.
On the live site, the browser console is the single most useful tool you have. A red message like Uncaught ReferenceError, undefined is not a function, or Failed to fetch usually names the exact file or call that broke. Copy that message — it's the search term that solves most of these.
2. Missing environment variables in production (the #1 cause)
This is, by a wide margin, the most common "works in preview, broken live" report. Bolt's preview and your local machine have your environment variables; your deployment host does not unless you set them there too. So a key that's present in preview is simply undefined in production, and any code that depends on it fails.
Fix: Add every variable your app needs to the host's environment settings — Netlify: Site settings → Environment variables; Vercel: Settings → Environment Variables. Then trigger a fresh deploy: env vars are read at build time, so a site built before you added them won't see them.
There's a second trap that bites almost everyone. In a Vite app (which most Bolt projects are), only variables prefixed VITE_ are exposed to browser code. Anything without that prefix stays server-only and reads as undefined in the front-end. Frameworks have their own prefix — NEXT_PUBLIC_ for Next.js, PUBLIC_ for SvelteKit/Astro.
# A browser-visible value MUST be prefixed:
VITE_SUPABASE_URL=https://yourproject.supabase.co
VITE_SUPABASE_ANON_KEY=eyJhbGciOi... # anon key is safe in the browser
# This will be undefined in front-end code (no VITE_ prefix):
SUPABASE_URL=https://yourproject.supabase.co
VITE_ / browser-exposed variables. A real secret — a service-role key, a Stripe sk_ key, an API secret — must live only in a server-side environment variable, never in the repo and never in a chat prompt. If one has leaked, rotate it immediately.3. Blank white screen, or the page loads then nothing
A blank page after a successful deploy almost always comes down to one of three things — and the console tells you which.
- A runtime JavaScript error thrown only in production. A minified build, a missing env var, or a value that's
undefinedin prod can crash the first render, leaving an empty page. Open the console: the red error names the cause. (Often it traces straight back to #2.) - Client-side routing that 404s on refresh. Your app works when you click around from the home page, but loading
/dashboarddirectly — or hitting refresh on it — gives a 404 or blank. That's because the host looks for a real file at that path and there isn't one; a single-page app needs every path to serveindex.htmland let the front-end router take over. - Wrong base path. If the app is deployed under a sub-path or the Vite
baseis misconfigured, the page can't find its JS/CSS bundles and renders nothing. Confirm assets load with a200in the Network tab.
Fix for the SPA refresh 404 — add a fallback redirect so every route serves your app's entry file. On Netlify, create public/_redirects (it gets copied to the build output):
/* /index.html 200
On Vercel or Cloudflare Pages a SPA is usually detected automatically, but if not, add a rewrite of all paths to /index.html. After adding it, re-deploy and test by loading a deep link directly and hitting refresh.
4. It builds locally but fails on the host
The build runs clean on your machine, then dies on the host. The host's build server is a different, stricter, case-sensitive Linux environment — and that difference surfaces bugs your laptop hides. Read the host's build log; the failing line is usually explicit. The four usual culprits:
- Node version mismatch. Your machine runs one Node version; the host defaults to another, and a dependency won't build on it. Pin the version — add an
enginesfield inpackage.jsonor setNODE_VERSIONin the host's environment so local and host match. - Case-sensitive import paths. macOS and Windows treat
./Buttonand./buttonas the same file; the host's Linux build server does not. An import whose casing doesn't exactly match the filename builds fine for you and fails on deploy withModule not found. Make every import match the file's real capitalisation. - A dependency that isn't in
package.json. If a package got installed locally but never saved as a dependency, the host's clean install won't have it. Make sure it's listed underdependencies(not justdevDependenciesif it's needed at build time). - A lockfile out of sync. If
package-lock.json/pnpm-lock.yamldoesn't matchpackage.json, a strict CI install (npm ci) fails outright. Run a fresh install locally to regenerate the lockfile, then commit it.
node_modules, run npm ci then npm run build. That mimics the host far better than your day-to-day dev server and surfaces most of these without burning deploy minutes.Live site down and you don't have hours to debug it?
Send me what's happening and I'll get your Bolt app back up — flat fee, quoted up front, reply the same day. Most production rescues are sorted within a day or two.
Get my app fixed → Flat fee · reply today · no retainer required5. API calls fail in production
The page loads but a feature is dead — data won't load, a save fails, login spins. Open the Network tab, trigger it, and read the failed request. A handful of causes account for nearly all of these:
- CORS. If the console says
blocked by CORS policy, your API didn't allow requests from your live domain. The API has to returnAccess-Control-Allow-Originfor your production URL (not justlocalhost) and answer the preflightOPTIONSrequest. - Calling
localhostor a dead preview URL. A base URL hard-coded tohttp://localhost:3000or to a temporary Bolt/StackBlitz preview URL works while you're developing and 404s (or refuses to connect) in production. Point it at the real production API URL — ideally via an env var, not a hard-coded string. - Missing or wrong keys. An API or Supabase key that was never set as a production secret (see #2) means every authenticated request is rejected. Confirm the production env has the right keys and that you re-deployed after adding them.
- Mixed content. A live
https://site calling anhttp://endpoint is blocked by the browser. Make sure every API URL ishttps.
6. An AI edit broke the build — roll back first, diagnose after
If everything was fine an hour ago and a Bolt edit broke it, do not start frantically editing live. The calm emergency move is to get the site working again by rolling back to the last good deploy, then diagnose with the pressure off.
- Roll back on the host. Netlify: Deploys → an earlier successful deploy → Publish deploy. Vercel: Deployments → the last working one → ⋯ → Promote to Production. Your live site instantly serves the known-good version while you investigate — no customer-facing downtime.
- Find what changed. Compare the broken deploy against the last working one. In your Git history (Bolt projects are Git-backed),
git diffbetween the two commits, or use the host's deploy diff, shows exactly which files the AI edited. The break is almost always in that small set. - Fix forward calmly. With the live site safe, reproduce the failure locally (
npm run build), fix the specific file the diff flagged, and only then deploy again.
7. Supabase / back-end connection issues
If your app uses Supabase and the page renders but is empty — no data, lists that never populate — the front-end is fine and the database connection or permissions are the problem. Two causes dominate:
- Wrong project URL or anon key in production. If
VITE_SUPABASE_URLorVITE_SUPABASE_ANON_KEYis missing, blank, or points at a different project in production, every query silently fails or returns nothing. Confirm the production env has the values from Supabase → Project Settings → API, and that you re-deployed after setting them (#2). - Row Level Security is blocking reads. Supabase blocks all access by default until you add policies. If you tested with RLS off (or as an authenticated session that prod doesn't have), queries that worked in preview return an empty set in production. Check Supabase → Authentication → Policies and add a policy that permits the reads your app needs. A successful request that returns
[]for data that clearly exists is the classic RLS fingerprint.
How to stop it breaking again
Production breaks on AI-built apps are uniquely nasty because they're silent: the deploy says "Published," everything looks fine to you, and the first you hear of it is a user (or no user at all, just a quiet drop in signups). Two habits prevent most of the pain:
- Run a real synthetic test of your critical flows on a schedule — load the page, sign in, do the one thing the app exists to do — so you find out within minutes when a deploy breaks something, not days later.
- Keep an offsite backup so a bad edit or a wiped database is an "undo," not a disaster.
That's exactly what Backstop does — it runs your real critical flows as live browser tests around the clock, watches your back-end, and alerts you in plain English the moment one breaks, so you hear it from us before you hear it from a customer.
Catch the next break before your users do.
Join the waitlist for Backstop — monitoring + offsite backup built for apps made on Bolt, Lovable, Replit and Supabase. We'll email you at launch, nothing else.
Frequently asked
It works in Bolt preview but breaks on my live site — why?
The number one cause is missing environment variables. Keys you set in Bolt or locally aren't automatically set on your deployment host — add them there and re-deploy. And remember client-side values need a VITE_ (or NEXT_PUBLIC_ / PUBLIC_) prefix to be visible to browser code, or they read as undefined (#2).
My deployed Bolt app is a blank white screen.
Usually a runtime JavaScript error or client-side routing that 404s on refresh. Open the browser console on the live site and read the red error. If only deep links or refreshes fail, add an SPA fallback redirect (/* /index.html 200 on Netlify) so every path serves index.html (#3).
It builds locally but fails on the host.
Read the host's build log for the exact failing line. The usual causes are a Node version mismatch, case-sensitive import paths that work on Mac/Windows but fail on the host's Linux build, a dependency missing from package.json, or a lockfile out of sync. A clean local npm ci && npm run build reproduces most of them (#4).