©Code byMilanParmar

Bolt app works in preview but breaks after deploy: fixes

Why Bolt's preview and a deployed build behave differently, a symptom-to-fix table, the environment variable rules, the _redirects and vercel.json files, build and publish folder settings, Supabase sign-in URLs, CORS and mixed content, and a pre-publish checklist.

13 min read

A Bolt app that works in preview but breaks after deploy almost always has one of four problems: the VITE_variables never reached the host, so the page is blank; there's no rewrite to index.html, so refreshing gives a 404; the host publishes the wrong folder; or Supabase still sends users to the preview address. The browser console tells you which.

This guide is for founders who built an app in Bolt.new, hit Publish or exported it to Netlify or Vercel, and got a white page, a 404, or "Invalid API key" where the preview worked fine. Each section is one cause, with the exact file or setting that fixes it, and the order follows how often I see each one. If your app was built in Lovable rather than Bolt, the hosting steps are in how to move a Lovable app to your own hosting; the Supabase and Vite parts below apply to both.

Why a Bolt app works in preview but not when deployed

Bolt's preview runs a development server inside your browser tab. That server reads the project's .env file, answers every URL by handing it to the app, and serves source files as they are. A deploy is different in all three ways. The host runs npm run build, which turns the source into static files in a folder called dist, and then serves only those files. There is no development server to fill in the gaps.

So three things that were free in preview become settings you have to make: variables have to be set on the host before the build, the host has to be told to serve index.htmlfor every path, and it has to be pointed at the right output folder. A fourth is outside the host entirely: Supabase has a list of addresses it trusts, and the deployed address isn't on it yet. None of these is a bug in your code, which is why asking Bolt to "fix the deploy" often changes the code and fixes nothing.

Find the cause: browser console and Netlify deploy log

Two places hold the answer. First, open the live address in a private browser window, so a cached copy from an earlier deploy can't fool you, and open the developer tools (F12, or right click and Inspect). Read the first red line in the Console tab, then open the Network tab, reload, and check the status of the main JavaScript file. Second, on Netlify, Netlify's docs say every deploy has a detail page with its deploy log, including everything your build printed and whether the deploy succeeded or failed, and a summary above it that shows how many files were uploaded and the status of your redirects. Vercel shows the same under the deployment's Build Logs.

Bolt app broken after deploy: symptom, cause, and fix
What you seeCauseFix
Blank page; console says supabaseUrl is required or a value is undefinedThe VITE_variables aren't set on the hostAdd them with the exact names, then build and deploy again
Blank page; the main .js file is a 404, or comes back as HTMLWrong publish folder, or a rewrite catching asset requestsPublish dist; keep the rewrite as the last rule
Blank page; a red error from your own codeA crash the preview never hit: logged-out user, empty tableRead the stack trace, guard the empty case, add an error boundary
Home page works; refreshing /dashboardgives Netlify's "Page not found" No rewrite to index.htmlAdd public/_redirects or vercel.json
401 Invalid API key on requests to supabase.coWrong key: the secret key, a stale key, or another project'sPaste this project's publishable key, redeploy
Sign-up email or OAuth lands on the preview or localhostSupabase Site URL and redirect URLs still point at previewSet them to the live domain in Supabase
blocked by CORS policy or Mixed Content in the consoleA backend that only allows the preview origin, or an http APIAllow the live origin; call the API over https
Deploy log: build failed, or "Could not find a build output directory"Wrong build command, output folder, or Node versionnpm run build, dist, set NODE_VERSION
Home loads unstyled; assets 404 under a subfolderVite's basepath doesn't match where the app livesSet base in vite.config.ts, or deploy at the root

If the console is empty and the page is still blank, view the page source. If you see <script type="module" src="/src/main.tsx">, the host served the source index.html rather than the built one, which is the publish folder problem below.

Bolt app blank page after deploy: environment variables

This is the most common cause, and the one the Netlify forum thread titled "Blank page after deployment" shows: a Bolt app deployed to Netlify, a white page, and Uncaught Error: supabaseUrl is requiredin the console. The app reads its Supabase address from a variable that exists in Bolt's preview and nowhere else. Three rules explain it.

  1. Bolt doesn't send its variables to the host. Netlify's guide to deploying a Bolt app says Bolt does not pass its environment variables to Netlify, so you add them under Site configuration yourself. Vercel's guide to deploying a Bolt export says the same of the zip: Bolt doesn't include the values from its Secrets panel in the export. And Netlify's docs say its build system does not read .env files at all, so a .env committed to GitHub changes nothing.
  2. Only VITE_ names reach the browser. Vite's docs say variables prefixed with VITE_ are exposed in client-side code after bundling; the default prefix is VITE_. A variable named SUPABASE_URL is invisible to a Bolt app that reads import.meta.env.VITE_SUPABASE_URL. Names have to match exactly, including case.
  3. Values are baked in at build time.Vite's docs say these constants are statically replaced at build time, and Netlify's docs say environment variable changes require a build and deploy to take effect. Adding the variable and reloading the site does nothing; you have to trigger a new deploy.

So: open Bolt's .env file, copy every VITE_name and value into the host's environment settings, with the production environment ticked, then redeploy. On Netlify that's Site configuration, then Environment variables; on Vercel it's Settings, then Environment Variables, with Production selected. The Netlify CLI can import the file in one go with netlify env:import .env.

Never put a secret in a VITE_ variable

Vite's docs warn that VITE_*variables should not contain sensitive information such as API keys, because anyone can read them out of the deployed JavaScript. The Supabase URL and publishable key are designed to be public, and that's fine. A Stripe secret key, an OpenAI key, or the Supabase secret key is not. If Bolt put one in .env with a VITE_prefix, it needs to move into a server function before you deploy, not just into the host's settings with the same name.

Supabase Invalid API key after deploying a Bolt app

A 401 with Invalid API key from supabase.coon the live site, when the preview works, means the deployed build is sending a key Supabase won't accept. In the Network tab, open a failing request and read the apikey header. One of these is wrong:

  • It's the secret key.Supabase's API key docs say a secret key doesn't work in a browser: Supabase checks the request and returns 401 Unauthorized. If the value on the host starts with sb_secret_, or is the old service_role key, replace it with the publishable key, which starts with sb_publishable_, or the older anon key.
  • It's from a different project.Bolt's docs say new projects use a Bolt database by default, and a database claimed into Supabase becomes a new Supabase project. The URL and key on the host have to come from that project's API settings, not from an older one.
  • It was pasted with a stray character, or the key was rotated in Supabase after you copied it. Copy it again from Project Settings, then API Keys, and compare the first and last few characters with the header the browser sent.

After any change, redeploy. The key is built into the JavaScript, so the live site keeps sending the old one until a new build runs.

Bolt app 404 on refresh: the _redirects file

A Bolt app built with React is a single page app: there is one real file, index.html, and React Router draws every page from it in the browser. Clicking from the home page to /dashboard works because no request leaves the browser. Refreshing /dashboard, or opening a link to it from an email, asks the host for a file called dashboard, which doesn't exist. Netlify answers with its own "Page not found".

The fix is a rewrite that serves index.htmlfor every path. Netlify's docs give the rule for single page apps and say it should typically be the last rule listed, so other redirects still work. Put it in a file named _redirects, with no extension, in the project's public folder, which Vite copies into dist:

public/_redirects
/*    /index.html   200

Or in netlify.toml at the root of the project, which also fixes the build settings in the next section:

netlify.toml
[build]
  command = "npm run build"
  publish = "dist"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

On Vercel, Vercel's Vite docs give the same rule as a vercel.json at the root of the project:

vercel.json
{
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}

Two mistakes to avoid. Netlify's docs say the _redirects file has to end up in the publish directory, the folder you deploy. A file at the project root, outside public, is never copied into dist, and the rule silently does nothing. And a rule placed above your other rules, or written with a trailing ! to force it, can catch requests for JavaScript and CSS files too, which turns a 404 on refresh into a blank page everywhere. Check the deploy summary: it reports how many redirect rules were processed.

Build command, publish directory, and Node version

When the deploy log shows a failure, or the live page is blank with a 404 on the main script, the host's build settings don't match the project. Netlify's build docs define the build command as the command that builds your site, for example npm run build, and the publish directory as the folder with the deploy-ready files it generates, adding that only files in the publish directory are deployed. For a Bolt app that's dist. Netlify's Bolt guide puts it plainly: Vite outputs dist, Create React App outputs build, and pointing Netlify at the wrong folder serves an empty page.

Dragging the wrong folder onto Netlify

If you deploy by drag and drop, as Bolt's own publishing docs suggest when the Netlify integration fails, drop the dist folder, not the project. In a Netlify forum thread, a Bolt user got a 404 on every deploy method; a staff member spotted from their screenshot that the upload had the CSS and JavaScript files but no index.html, and said the correct structure is dist/index.html plus an assets folder. Run npm run build locally first and check the folder before you drag it.

Build works in Bolt, fails on the host

Bolt's publishing docs list a "Could not find a build output directory" error, which means the build never produced dist; the fix they give is to paste the error into the chat. On Netlify, Netlify's Bolt guide says a build that works in Bolt but fails on Netlify is usually a Node version mismatch, fixed with a .nvmrc file or a NODE_VERSIONvariable. Other common lines in the log: an import whose capital letters don't match the file name, which Bolt's preview tolerated and Linux doesn't, and a TypeScript error that the preview showed as a warning. Running npm run build on your own computer shows the same errors faster than a deploy does.

Assets 404 when the app lives in a subfolder

If you deploy under a path like yoursite.com/app/, the HTML loads but every script and stylesheet is a 404, because Vite's docs say the base option defaults to /, so the built page asks for /assets/… at the domain root. Set base: "/app/" in vite.config.ts, and give React Router the same basename. Or deploy at the root of a subdomain, which is simpler.

Login works in Bolt preview but not on the live site

If sign-up emails open the Bolt preview address or localhost:3000, or Google sign-in bounces back to the wrong place, Supabase doesn't know about the deployed address yet. Supabase's docs say the Site URL is where users are sent by default after authentication, tell you to change it from http://localhost:3000 to your production URL, and say any other address the app redirects to has to match the Redirect URLs list. In Supabase, open Authentication, then URL Configuration:

  1. Set the Site URL to the live address, for example https://app.yourdomain.com
  2. Add the live address with /** after it to Redirect URLs
  3. For Netlify deploy previews, Supabase's docs give the wildcard https://**--your-site.netlify.app/**; for Vercel, https://*-your-team.vercel.app/**
  4. Leave the preview address in the list while you still use Bolt's preview to test
  5. Add the live domain to Google's or GitHub's OAuth settings as well

This fixes where users land. If they land in the right place and then see a spinner forever, that's a different problem, inside the app's auth code, and the causes are in why an app hangs after login, which applies to Bolt apps on Supabase too.

CORS errors and mixed content after deploying a Bolt app

Two console messages come from the browser's security rules rather than your code. blocked by CORS policymeans the app called a backend that doesn't allow requests from the new address. Supabase allows every origin, so this usually means a separate API: a Node server Bolt wrote, a third-party service with an allowed-domains list, or a backend that only allows Bolt's preview origin. Netlify's Bolt guide names that last one as a cause of a feature that works in preview and breaks live. Add the live origin, with https://and no trailing slash, to that backend's allowed list.

Mixed Content means an https:// page tried to call an http://address. MDN's mixed content page says browsers block fetch() and XMLHttpRequest requests over HTTP from a secure page, while images and media are upgraded instead. Search the code for http:// and localhost: a hard-coded development address is the usual cause, and it belongs in a VITE_API_URL variable with an https:// value on the host.

One more thing that can't move. Bolt's Netlify docs say Netlify can't host a database or a traditional backend, and that projects needing one should stay on Bolt hosting. A Bolt app using a Bolt database, or a server Bolt runs for you, won't have those pieces on Netlify or Vercel; the front end deploys and every data call fails. Those apps need the database claimed into Supabase, or the server deployed somewhere of its own, before the front end moves.

Checklist before you publish a Bolt app

Every item below is a setting from this post, in the order it bites. Ten minutes on this list before you share the link saves the round of "it worked yesterday" messages afterwards.

Deploy settings are the part of a launch you can check in an hour. The parts you can't see from the browser, such as which tables anyone with that public key can read, are on the vibe-coded app launch checklist.

When a Bolt deploy problem needs a developer

If the table above names your symptom, fix it yourself: each is one file or one setting, and Bolt can write the file if you tell it exactly which one. Get help when the fixes work and the app still misbehaves on real traffic, when the console shows an error from your own code that you can't trace, when secrets turned out to be in VITE_variables, or when the app has paying users and you'd rather not learn Netlify on them.

A proper deploy on hosting you control, with environment variables, monitoring, and backups set up, is part of my Production Sprint, after a Launch-Ready Review that checks hosting alongside Supabase access rules, logins, and secret keys. The deploy is usually the smallest item on that list. The Chat Company came to me as a buggy demo generated with AI tools; I kept about 20% of it, rewrote the rest, and launched in nine weeks, and it now serves 30+ businesses. What each step costs is in the cost to fix a vibe-coded app.

Not sure whether you need any of that? Start with when a vibe-coded app needs a developer. Otherwise, send me the live link and a screenshot of the console and I'll tell you which row it is.

Sources

  1. Deploy your Bolt app to Netlify: variables, publish folder, redirect rule, Netlify Knowledge Base
  2. Netlify integration: publishing from Bolt, no backend on Netlify, Bolt Docs
  3. Publishing issues: build output directory, Netlify, forked projects, Bolt Docs
  4. Publishing to Bolt hosting: changes need Update, Bolt Docs
  5. Supabase integration: Bolt databases by default, claiming, Bolt Docs
  6. Deploy a Bolt.new app with Vercel Drop: secrets not exported, Vercel Knowledge Base
  7. Vite on Vercel: rewrite for single page apps, Vercel Docs
  8. Rewrites and proxies: history pushState and single page apps, Netlify Docs
  9. Redirects overview: save _redirects to the publish directory, Netlify Docs
  10. Environment variables: .env files not read, build and deploy to apply, Netlify Docs
  11. Build configuration: build command, publish and base directory, Netlify Docs
  12. Deploy overview: the deploy log and deploy summary, Netlify Docs
  13. Env variables and modes: VITE_ prefix, static replacement at build, Vite Docs
  14. Shared options: base defaults to /, envPrefix defaults to VITE_, Vite Docs
  15. Redirect URLs and the Site URL, with Netlify and Vercel wildcards, Supabase Docs
  16. API keys: publishable keys are safe online, secret keys fail in a browser, Supabase Docs
  17. Mixed content: fetch and XMLHttpRequest over HTTP are blocked, MDN Web Docs
  18. Blank page after deployment: supabaseUrl is required, Netlify Support Forums
  19. Unable to upload my Bolt project to Netlify: dist/index.html missing, Netlify Support Forums
Milan Parmar

The developer

Freelance full-stack developer in Bengaluru with 5+ years of experience. I redesign websites, take over broken apps, and build SaaS products, with 18 case studies to show for it.

FAQs

Can I deploy a Bolt app that uses a Bolt database to Netlify?

Not the database part. Bolt's docs say Netlify can't host a database or a traditional backend, and that projects which need one should stay on Bolt hosting. Bolt's docs also say new projects use a Bolt database by default. If you want the app on Netlify or Vercel, claim the database into a Supabase project first, which needs a Pro or Teams plan, then point the deployed app at it.

Why did my Bolt app stop deploying after I duplicated the project?

Because the copy isn't linked to Netlify. Bolt's publishing docs say a forked or duplicated project loses the Netlify connection, and reconnecting creates a new Netlify site. Treat the copy as a new deployment: reconnect it, add the environment variables again on the new site, and point any custom domain at the new site rather than the old one.

Why doesn't my published Bolt app show my latest changes?

On Bolt hosting, publishing is a snapshot. Bolt's docs say changes you make after publishing aren't applied to the live site until you click Update in the Publish menu. On Netlify or Vercel connected to GitHub, the site rebuilds on each commit, so check that the commit actually reached the repository and that the latest deploy in the host's dashboard succeeded rather than failed.

Is it safe that my Supabase key is visible in the deployed Bolt app?

Yes, if it's the publishable key, which starts with sb_publishable_, or the older anon key. Supabase's docs describe it as safe to expose in a web page: anyone can read it, so it only reaches what Row Level Security allows. The danger is the secret key, which bypasses every policy and must never be in a VITE_ variable or in the browser at all.