
You prompted your way to a working app in Bolt.new. It ran fine right there in the browser, WebContainer spun it up instantly, no local setup, no config, just a working preview. Then you deployed it and something broke. A blank screen. A login that never completes. Data that used to be there and now just isn’t. This is common enough in 2026 that it’s basically the defining gap in AI-assisted building: what runs perfectly inside StackBlitz’s sandbox doesn’t automatically survive contact with a real host.
If your Bolt.new app isn’t working, it’s almost always one of five things: environment variables that never made it out of the editor and onto your hosting provider, Supabase Row-Level Security that’s disabled or missing policies, OAuth redirect URLs still pointing at localhost or the StackBlitz preview domain, a Stripe webhook registered against the wrong URL, or a mismatch between what Bolt’s WebContainer assumes and what your actual Netlify or Vercel build config expects.
None of this is a Bolt.new problem exactly. It’s the standard gap between a browser-based dev sandbox and a real production host, and it hits AI-generated apps harder than hand-coded ones because the tool writing your code has no visibility into your actual production domain when it generates the app.
This guide covers seven specific errors with exact fixes, why preview and production diverge so sharply, when it’s worth paying someone instead of losing a weekend to it, and a checklist for your next build. If you’d rather just have it fixed, KrishaWeb runs an AI Build Rescue service built for exactly this.
Bolt.new runs your entire app inside a WebContainer, a full Node.js environment that executes right in your browser tab via StackBlitz’s technology. That’s what makes the instant preview possible, no install, no terminal. It’s also exactly why production feels like a different world once you leave it: the WebContainer handles a dozen things invisibly that a real host won’t do for you automatically.
| Aspect | Preview (StackBlitz WebContainer) | Production Environment |
| Environment variables | Auto-injected from Bolt’s own settings | Must be manually configured on your host |
| Supabase RLS | Often left disabled during testing | Must be enabled with real policies |
| OAuth redirect URLs | Points at localhost or the preview domain | Must point at your production domain |
| CORS | Permissive for development | Enforced strictly |
| Database migrations | May not be run at all | Must be explicitly deployed |
| API keys | Test mode | Live-mode secrets |
| Build config | WebContainer handles it silently | Needs explicit Netlify or Vercel configuration |
Three root causes account for most of what actually breaks:
You deploy, and instead of your app, you get a blank screen. Console shows something like “VITE_SUPABASE_URL is undefined.” The preview link, still fine. Your actual production URL, dead.
The reason is simple: variables set inside Bolt’s own environment don’t travel anywhere on their own. Your hosting provider has no idea they exist until you tell it.
Here’s the fix:
1. In Bolt, open the .env file or Project Settings, then Environment Variables, and write down everything there, especially VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY.
2. Go to your hosting dashboard. On Netlify, that’s Site Settings, then Environment Variables. On Vercel, it’s Project, then Settings, then Environment Variables, scoped specifically to Production.
3. Add every variable there with production values, not whatever was sitting in the editor.
4. For Supabase specifically: VITE_SUPABASE_URL is your project URL, VITE_SUPABASE_ANON_KEY lives under Supabase’s Settings, then API.
5. Redeploy, clearing the build cache rather than relying on a stale one.
6. Hard-refresh the browser (Ctrl+Shift+R or Cmd+Shift+R) before you conclude it’s still broken.
One thing worth knowing that trips people up: client-side frameworks only expose variables with the right prefix. Vite needs VITE_, Next.js needs NEXT_PUBLIC_. Name a variable wrong and it simply won’t show up in the browser bundle, no error, just silence.
Going forward, keep a .env.example file in your repo, and separate anything that’s actually a secret from the public VITE_* variables meant for the client.
If you’ve added everything you can think of and it’s still broken, there’s usually a second issue underneath the first, worth a quick professional look rather than more guessing.
This one’s a little sneakier than it sounds, because it doesn’t always throw an error. If RLS is enabled but there’s no SELECT policy, Supabase typically returns an empty result set with a 200 status, not a 403. Your app just quietly shows nothing. Where you do get an explicit error is on INSERT or UPDATE: “new row violates row-level security policy,” a 403-style rejection from PostgREST.
Bolt.new, like most AI builders wired into Supabase, generates your tables without turning RLS on by default. That’s the standard state for a new Supabase table until someone flips it deliberately.
Here’s how to fix it. In the Supabase dashboard, go to Table Editor, click your table, open Policies. No policies listed means RLS is off, or on with nothing granting access, either way, check both. Enable it:
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;
Add a policy per operation, scoped to whoever’s actually signed in:
CREATE POLICY “Users read own data”
ON your_table
FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY “Users insert own data”
ON your_table
FOR INSERT
WITH CHECK (auth.uid() = user_id);
CREATE POLICY “Users update own data”
ON your_table
FOR UPDATE
USING (auth.uid() = user_id);
CREATE POLICY “Users delete own data”
ON your_table
FOR DELETE
USING (auth.uid() = user_id);
Repeat for every table with a user_id column.
You can also just ask Bolt directly: “enable Row Level Security on all tables and create policies so users can only access their own records” usually gets a workable first pass, though check the generated SQL against your actual schema before trusting it outright.
Audit this before deploying, not after discovering it live. Every table touching user data needs four real policies, not just RLS switched on with nothing behind it.
Ten-plus tables with genuine relationships between them turns this from a quick fix into an actual audit, worth a second set of eyes before real user data is anywhere near exposed.
Login works fine in the Bolt preview, fails the second you deploy. You’ll see “redirect_uri_mismatch” or “Invalid redirect URL,” and nobody can sign in with Google, GitHub, or whatever provider you wired up.
The redirect URLs in both Supabase and your OAuth provider are still referencing localhost or the StackBlitz preview domain, not wherever your app actually lives.
To fix it:
1. In Supabase, go to Authentication, then URL Configuration. Set the Site URL to your real domain, https://yourapp.com, no trailing slash. Under Redirect URLs, add https://yourapp.com/** and https://yourapp.com/auth/callback.
2. In your OAuth provider’s console, Google Cloud Console, GitHub’s app settings, whatever it is, add both https://<your-project-ref>.supabase.co/auth/v1/callback and https://yourapp.com/auth/callback as authorized redirect URIs.
3. Save and redeploy.
4. Test with an actual login, not the preview flow.
Write down every redirect URL for every provider in a README before you deploy. Two minutes now saves rediscovering this from scratch later.
Multiple OAuth providers at once gets error-prone fast. A rescue team can typically sort and verify all of it within an hour.
Payments work in test mode, fail once live. Webhook errors read “Invalid signature” or “Webhook endpoint not found,” and orders just don’t update after a successful charge.
The webhook’s still pointed at your Bolt preview URL with a test-mode secret, not your live production URL with a live-mode secret.
1. In the Stripe dashboard, go to Developers, then Webhooks, remove the endpoint pointing at the preview URL.
2. Add a new one pointing at your actual production URL, something like https://yourapp.com/api/webhooks/stripe.
3. Switch from test mode to live mode.
4. Update STRIPE_WEBHOOK_SECRET in your environment variables to the production secret Stripe gives you.
5. Redeploy, test with a real transaction.
Keep test and production as genuinely separate Stripe projects rather than flipping one back and forth. Much harder to mix up.
Treat this one as urgent. A broken webhook means silent order failures, and once real money is moving through the app, get someone to check the whole Stripe integration, not just the webhook, PCI handling included.
The build fails on Netlify or Vercel even though it worked fine in Bolt’s preview. You’ll see “Build failed,” “Publish directory not found,” or, if the build did succeed, SPA routing that breaks the moment someone refreshes on a deep link.
Bolt’s WebContainer handles build configuration invisibly. Your actual hosting provider needs to be told explicitly what to run and where to find the output.
For a typical Vite plus React Bolt project, set:
Add SPA routing so deep links don’t 404 on refresh:
Confirm the .nvmrc file actually exists and matches what your project needs. Redeploy. Test routing specifically by refreshing on a few different deep links, not just the homepage.
Worth noting: Bolt also offers one-click deployment straight to Netlify from the editor, and its own Bolt Cloud hosting under a *.bolt.host domain, both of which sidestep some of this config work. If you’re hitting this error, you’ve likely exported to GitHub and connected your own hosting account, which gives you more control but also means none of that configuration happens for you automatically.
Test the deploy against something that actually resembles production before sending real users to it, rather than discovering the gap live.
Consistently failing builds or a more complex monorepo setup is a fair point to bring in help, this kind of config debugging usually resolves in an hour or two once someone’s actually looked at it.
Console shows “has been blocked by CORS policy.” The call worked fine in preview, dies once deployed, and the network tab is full of failed requests.
Supabase Edge Functions and third-party APIs generally ship with loose CORS settings during development. Production tightens up, and if nobody updated the allowed origins to include your real domain, the browser blocks the request before it ever reaches your server.
Find the specific failing endpoint from the console error. If it’s your own Supabase Edge Function, add the right headers:
return new Response(JSON.stringify(data), {
headers: {
‘Access-Control-Allow-Origin’: ‘https://yourapp.com’,
‘Access-Control-Allow-Methods’: ‘GET, POST, PUT, DELETE’,
‘Access-Control-Allow-Headers’: ‘Content-Type, Authorization’,
},
});
If it’s a third-party API you don’t control, ask them to whitelist your production domain, or route the call through your own Edge Function so the browser never talks to that API directly. Redeploy, retest.
Never put API secrets in client-side code. Keep anything sensitive behind a server-side Edge Function, which conveniently sidesteps most CORS headaches too.
Several external APIs, each with their own CORS quirks, can eat a full day on your own. A rescue engagement usually maps and fixes all of them in one pass.
“Failed to compile.” A pile of TypeScript errors. The app just refuses to deploy no matter how many times you retry.
Somewhere along the way, a manual edit or an AI-generated change introduced invalid syntax, a missing dependency, or a case-sensitive import path the dev server tolerated but a strict production build won’t.
1. In Bolt, open the Version History panel (click the project name, then Version History).
2. Roll back to the last version you know actually worked.
3. Reapply your changes one at a time, testing after each, not all at once.
4. Open the browser console (F12) and read the real error, not just the summary.
5. Fix the first error, not the last. Later ones are usually just noise cascading from the first.
6. If the error mentions an undefined environment variable, go back to Project Settings, then Environment Variables, and confirm the key is actually set and spelled correctly.
7. Before deploying again, verify the build succeeds locally by running npm run build in Bolt’s own Terminal.
Keep prompts narrow and check version history after each one, instead of hand-editing code at the same time the AI is generating changes. Mixing the two is where most of these breakages start.
If enough edits have piled up that you genuinely can’t tell what broke it, that’s a fair time to bring in someone who can diff the history and isolate the actual regression.
Worth stating plainly, since it’s the root of most of the confusion: the WebContainer you’re building in runs on different environment variables, permissions, and validation rules than the app you actually ship.
None of this means Bolt is broken. It means the editor and the deployed app are, structurally, two different environments, and treating a clean preview as proof of production-readiness is the actual mistake behind most “it worked five minutes ago” moments.
DIY is fine for one isolated error. It gets harder once several stack together, which happens more than you’d expect, because they cluster. Fix the environment variables and the RLS problem underneath often surfaces right after.
Situations where paying someone genuinely beats a lost weekend:
We built this because “my Bolt app broke and I don’t know why” turned out to be something we saw over and over, not a rare event. The engagement generally includes:
Most engagements run one to two business days: roughly an hour to diagnose, four to six hours for standard fixes, another two to three for a proper security pass. Pricing depends on scope, usually $2,000 to $10,000, and we’ll give you a real number once we’ve actually looked at what’s wrong.
Book a call with KrishaWeb’s AI Build Rescue team if this sounds like where you’re at.
Most of this is preventable with about twenty minutes of deliberate checking before you deploy:
Preview runs in a WebContainer that auto-injects environment variables, often leaves RLS disabled, and allows loose CORS. Production needs all of that configured properly. The usual suspects: missing env vars, disabled RLS, stale OAuth redirects, and a build config that doesn’t match your actual host.
Enable RLS on every table with user data using ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;, then add SELECT, INSERT, UPDATE, and DELETE policies scoped to auth.uid() = user_id. Note that a missing SELECT policy usually shows up as an empty result, not an error, while INSERT or UPDATE without a matching policy throws an explicit rejection.
At minimum, VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY, and, server-side only, SUPABASE_SERVICE_ROLE_KEY and SUPABASE_JWT_SECRET. These need to be added directly in your hosting provider’s environment settings, not just left inside Bolt, and the client-facing ones need the right prefix for your framework, VITE_ for Vite, NEXT_PUBLIC_ for Next.js.
In Supabase, set the Site URL to your production domain and add https://yourapp.com/** and https://yourapp.com/auth/callback as redirect URLs. In your OAuth provider’s console, add both the Supabase callback URL and your app’s own callback URL.
When you’ve got multiple errors at once, a real deadline, complex integrations, potential data loss, a suspected security issue, or you’ve already tried the obvious fixes and it’s still broken. A rescue engagement typically wraps this up in one to two business days instead of open-ended trial and error.
Simple fixes, environment variables and RLS on their own, usually run $2,000 to $4,000. More involved rescues covering multiple integrations and a full security audit run closer to $5,000 to $10,000. KrishaWeb can give you an exact number after a quick look.
Sometimes. A well-worded prompt can get it to enable RLS or patch a build error. It generally can’t fix things outside the app itself, environment variables on your host, OAuth provider settings, Stripe webhook configuration, because it doesn’t have access to any of that.
Run through the checklist above before every deploy: document environment variables, enable RLS everywhere needed, verify every OAuth redirect URL, point Stripe webhooks at production, configure CORS, set your build config explicitly, run migrations, audit security, back up the database, and write down what you did.
Bolt.new apps break in production for a small, predictable set of reasons: environment variables that didn’t travel with the deploy, RLS that’s off or missing policies, OAuth redirects still stuck on localhost, Stripe webhooks aimed at the wrong URL, and a build config that assumes the WebContainer’s doing work your actual host isn’t doing. Most single-issue cases, the fixes above will handle on their own.
It gets harder once several of these stack together, or there’s a real deadline, real money moving through Stripe, or user data sitting behind an RLS policy that may or may not actually be working. That’s usually where DIY stops being the faster option.
Fix it yourself. Work through the errors above in order, testing after each change, not at the end. Get it fixed. Book a call with KrishaWeb’s AI Build Rescue team and have it diagnosed and repaired in one to two business days. A broken app in front of a customer or an investor costs more than the fix does.

Subscribe to our newsletter for the latest in web, design, and AI.