FixedLaunchBack

fix guide

AI-built app works in preview but breaks when deployed

·

All fix guides

The app works in the builder. You click Publish, or push it to Vercel or Netlify, and the live site is blank, half loaded, logs people out or shows data from nowhere. Nothing changed in the code, so it feels random.

It isn't random. The preview and the live site are two different copies of your app, built in two places, with two sets of settings. Almost every preview-only bug comes from one of those differences. This guide explains each difference, how to spot it in a few minutes, and the fix. It covers Lovable, Bolt, v0, Replit and Cursor apps on Supabase, Vercel or Netlify.

Work through it in order. Step 2 is the one that saves the most time: it turns "the app is broken" into one exact error, and the error points at the right step.

1. Why the preview and the live site behave differently

The preview runs inside the builder. The builder already knows your Supabase project, your keys and its own preview address, and it often runs the app in a development mode that forgives small mistakes.

The live site is a fresh build on a host. The host only has the settings you gave it. It builds in production mode, on Linux, with stricter checks. It serves your pages from its own rules about addresses. And it may talk to a different database than the preview.

Six things differ, and each one gets a step below: the environment variables (step 3), the addresses that other services trust (step 4), the build itself (step 5), how the host serves pages (step 6), the data and its rules (step 7), and which version of the code is live (step 8).

Prompting the builder with "it works in preview but not live" rarely helps, because the builder can only see the preview. It has no view of your host's settings or logs.

2. Get one exact error before you change anything

Open the live site in a private window. A private window has no saved login or old cached files, so you see what a new visitor sees.

Press F12 (or right-click, then Inspect) and open the Console tab. Reload the page. Read the first red line, not the last one. Later errors are usually knock-on effects of the first.

Then open the Network tab, reload, and look for rows in red. Click one and note the address it called and the status code: 401 or 403 means the request was refused, 404 means the address doesn't exist, 500 means the server code crashed, and a CORS message means a browser rule blocked it.

If the deploy itself failed, there is no live site to inspect. Open the failed deployment on your host and read the build log, scrolling up from the last line to the first error that names a file.

Write the error down word for word. You will paste it into searches, into the builder's chat, or send it to whoever helps you.

signs You have one red line of text, an address and a status code, or a build log line with a file name.

3. Environment variables the host doesn't have

This is the most common cause. Your app reads settings like the Supabase URL and key from environment variables. The builder fills them in for the preview. Your host only has the ones you added in its dashboard.

Vite apps (most Lovable and Bolt apps) read names that start with VITE_. Next.js apps (v0 and many Cursor apps) read NEXT_PUBLIC_ for anything the browser needs. Both bake these values into the code when the site builds. So after you add or change one, you have to redeploy. Vercel's docs say changes apply only to new deployments.

On Vercel, open Settings, then Environment Variables, and check each name is ticked for Production, not only Preview. Copy the names from your project's .env file or the builder's settings and compare them one by one, letter for letter.

A blank page with supabaseUrl is required in the console is this cause. So is a request to an address with undefined in it. The full checklist is in Environment variable undefined in production on Vercel and supabaseUrl is required: blank page on your live site.

signs The console says a value is required or undefined, or a request goes to an address containing undefined.

4. Addresses that only trust the preview

Several services keep a list of web addresses they trust, and while you built, that list held the preview address or localhost. The live domain isn't on it, so those services refuse it.

Supabase Auth: open Authentication, then URL Configuration. Set the Site URL to your live domain and add every address people sign in from under Redirect URLs, including the www version. Otherwise confirmation and magic-link emails open the preview or localhost. Supabase login works locally but fails in production covers all five sign-in checks.

Google sign-in: the Google OAuth client must list the exact redirect URI, or Google stops sign-in with redirect_uri_mismatch. With Supabase Auth, that URI is the Supabase callback. See Google sign-in redirect_uri_mismatch after deploy.

Firebase Auth has its own list of authorized domains. A missing live domain gives auth/unauthorized-domain. See Firebase auth/unauthorized-domain after deploy.

Edge functions and outside APIs can refuse requests from an origin they don't know, which shows as a CORS error in the console. See Supabase Edge Function CORS error on your live site.

signs Sign-in sends you to localhost or the preview, Google shows redirect_uri_mismatch, or the console shows a CORS or unauthorized-domain error.

5. A build that passes in the builder and fails on the host

The host builds the app from scratch, in production mode, on Linux. Four differences catch AI-built apps.

Type errors: Next.js stops the build on a TypeScript error that the preview ignored. Run npx tsc --noEmit to list them.

Letter case: your Mac treats Button.tsx and button.tsx as the same file. Linux doesn't, so an import with the wrong capitals fails with Module not found.

Missing packages: the code imports a package that package.json doesn't list. The preview had it installed. The host doesn't.

Node.js version: the host builds with the version in its settings, which may not match the one the app was written for.

The log line Command "npm run build" exited with 1 only says the build failed. The real error sits above it. Command "npm run build" exited with 1 on Vercel walks through all six causes, and Bolt app won't publish covers Bolt's publish step.

signs The deploy shows Error instead of Ready, and the build log names a file, a type or a module.

6. Pages that 404 on refresh

Clicking around the live site works, but refreshing an inner page or opening a shared link shows 404. The host is looking for a file at that address and has none.

For Vite apps from Lovable and Bolt, the fix is a rewrite that sends every address to index.html: 404 on refresh on Vercel.

For Next.js apps from v0 or Cursor, a rewrite is usually the wrong fix. The cause is a screen with no route folder, a dynamic page that only knows some ids, or a page that calls notFound() when its data comes back empty: v0 app shows 404 on refresh after deploying to Vercel.

signs Only the home page survives a refresh, or only records created before the last deploy open.

7. Different data, different rules

Check which database the live site talks to. It is common for the preview to use one Supabase project and the live site another, empty one, because someone copied a different URL into the host. Then logins fail for users who exist, and lists are empty. Compare the project reference in the Supabase URL on both sides.

Replit keeps a development database and a production database apart. Data you added while building may not be in production at all.

Then check the rules. While you build, you test as yourself, signed in, often as the owner of every row. Real users hit Row Level Security policies you never tested. A missing select policy shows an empty list with no error. A missing insert policy fails with new row violates row-level security policy. A missing update policy makes edits vanish on refresh. Supabase RLS errors in AI-built apps, decoded lists each one with its fix, and Supabase data not saving, no error covers saves.

Don't fix a policy error by turning RLS off or by putting the secret key in the browser. Both open your data to anyone. Is my vibe-coded app secure? Seven checks before launch explains why.

signs Lists are empty for new users and full for you, or the live Supabase URL differs from the one in the builder.

8. The live site runs an older version

Sometimes the bug is already fixed, and the fix never went live.

Lovable's docs say publishing deploys a snapshot, and changes aren't pushed to the live app on their own. Open Publish and choose Publish changes.

v0's docs say that for a project connected to GitHub, Publish opens or reuses a pull request, merges it and waits for the production deployment. If the merge or the deployment failed, the live site is older than the preview.

On Vercel, open Deployments and check the latest production deployment is Ready and built from your latest commit. On a custom domain, check under Domains that the domain points at that production deployment.

signs A change you can see in the preview is missing live, and the latest production deployment is older than that change.

9. Fix one thing at a time

Change one setting, redeploy, and test in a new private window. If you change three things at once and the site works, you won't know which one fixed it. If it gets worse, you won't know which one to undo.

If the builder's fixes keep changing the error, stop prompting after two or three tries. Go back to the last version that worked: History, then Revert in Lovable, Version history in Bolt, or a checkpoint rollback in Replit. Reverting brings back code, not data, so check your tables afterwards.

Keep a short log: what you changed, when you redeployed, what the console said after. If you hand the problem to someone, that log saves them an hour.

10. When to get help

Get help when you have the exact error and the steps above don't match it, when the fix needs code changes you can't judge, or when each attempt breaks something that worked.

Send whoever you ask the live URL, the page where it breaks, the steps to reproduce it, the exact error text, and the names of your environment variables. Never send passwords or key values. How to hire someone to fix a Lovable, Bolt or v0 app covers how to pick someone and give access safely.

To see what a diagnosis looks at, read the checks page.

Test it like a new user

  1. Open the live site in a new private window, not the builder's preview.
  2. Reload with the console open and check there are no red lines.
  3. Sign up as a brand new user with an email you have never used on the app.
  4. Create, edit and delete one record, then refresh and check each change stuck.
  5. Refresh an inner page, then open it from a link on your phone.

Common questions

Why does my AI-built app work in the preview but not after I deploy it?

The preview runs inside the builder with its own settings, keys and address. The live site is a fresh build on a host that only has what you gave it. Missing environment variables, unregistered live addresses and stricter builds cause most of these bugs.

What should I check first when my deployed app shows a blank page?

Open the live site in a private window, press F12 and reload with the Console tab open. Read the first red line. A message about supabaseUrl being required, or a request to an address with undefined in it, means the host is missing environment variables.

Why are lists empty on my live app but full in the preview?

Either the live site talks to a different, empty database, or Row Level Security has no select policy for real users. Compare the Supabase URL on both sides first. Then test as a new user, because you built the app signed in as yourself.

Still stuck?

Not sure this is the cause? Paste your app's link into the free scan. It lists what a visitor's browser can see, like leaked keys and exposed files, worst first. The score is free; every fix as a prompt for your builder is $9, one-time.

Want a person to look inside? See the diagnosis

More fix guides

See all fix guides