You built your app with Lovable, Bolt, Replit or Cursor. In the preview everything works. You deploy it to Vercel or Netlify, open the live link and get a blank screen, a 404, or a login that sends users to localhost.
The good news: it's almost never your whole app that's broken. Most AI-built apps are React + Vite (often with Supabase), and they tend to fail after deploy for the same few reasons.
Here are the 5 I see most often, and how to fix each one.
1. Environment variables exist on your machine, not on the host
Symptoms: blank screen, supabaseUrl is required, API calls to undefined/..., or features that silently do nothing.
Your project probably reads config like this:
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
Locally, those values come from your .env file. But .env is (correctly) not pushed to GitHub, so your host has no idea what they are.
Fix:
- Open your
.envfile and copy each variable name and value. - Vercel: Project → Settings → Environment Variables. Netlify: Site configuration → Environment variables.
- Add each variable with the exact same name.
- Redeploy. This step matters: Vite bakes these values into your code at build time, so adding them without rebuilding changes nothing.
Two rules while you're there:
- In Vite, only variables starting with
VITE_are available in the browser.SUPABASE_URLwon't work;VITE_SUPABASE_URLwill. -
Never put secret keys in a
VITE_variable. Everything with that prefix ends up in public JavaScript that anyone can read. With Supabase, the anon key is designed to be public; the service_role key must never be in your frontend.
2. Refreshing any page except the homepage gives a 404
Symptoms: the homepage loads fine, clicking around works, but refreshing /dashboard or sharing a link to /login shows 404 Not Found.
Your app is a single-page app. There is only one real file, index.html, and React Router handles the URLs in the browser. When you refresh /dashboard, the server looks for a file called dashboard, doesn't find one, and returns 404.
Fix: tell the host to always serve index.html.
Vercel: create vercel.json in the project root:
{
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}
Netlify: create public/_redirects containing:
/* /index.html 200
Commit, push, and refreshing any page will work.
3. Login redirects to localhost (or fails after sign-in)
Symptoms: users sign up or log in and land on http://localhost:3000 / localhost:5173. Magic links and password-reset emails point to localhost. Google login shows a "redirect URL not allowed" error.
Your auth provider still thinks your app lives on your laptop.
Fix (Supabase):
- Supabase dashboard → Authentication → URL Configuration
- Set Site URL to your live domain, e.g.
https://yourapp.vercel.app - Under Redirect URLs, add your live domain (and keep
http://localhost:5173if you still develop locally)
If you use Google or GitHub login, also add the live URL in that provider's OAuth settings.
4. The frontend still calls localhost for the API
Symptoms: works on your machine, but on the live site the network tab shows requests to http://localhost:5000/... failing, or CORS errors.
AI tools often hardcode the backend address while you're developing:
fetch("http://localhost:5000/api/orders")
That works on your laptop because your backend runs there. On a visitor's phone, localhost means their phone.
Fix:
- Deploy the backend separately (Render, Railway, etc.) and get its URL.
- Replace hardcoded URLs with an environment variable:
const API_URL = import.meta.env.VITE_API_URL;
fetch(`${API_URL}/api/orders`);
- Add
VITE_API_URLon your frontend host (see cause #1) and redeploy. - On the backend, allow your live frontend in CORS, e.g. with Express:
app.use(cors({ origin: "https://yourapp.vercel.app" }));
5. The build fails on the server but works locally
Symptoms: the deploy log shows Could not resolve "./components/Header" or Module not found, even though the file obviously exists.
Very often this is letter case. Windows and macOS usually treat Header.tsx and header.tsx as the same file. Vercel and Netlify build on Linux, where they are different files.
import Header from "./components/Header"; // file is actually header.tsx
Fix: make every import match the file name exactly, including capital letters.
If you renamed a file only by changing its case, Git may not have noticed. Rename it properly:
git mv src/components/header.tsx src/components/Header.tsx
Other quick checks when the build fails:
- Run
npm run buildlocally. If it fails there too, the error message tells you which file is broken. - Make sure the build command is
npm run buildand the output directory isdist(for Vite). - If the log mentions TypeScript errors, the AI may have left type errors that preview mode tolerated but the production build doesn't.
Quick checklist before every deploy
- [ ] All
.envvariables added on the host, then redeployed - [ ] No secret keys in
VITE_variables - [ ] SPA rewrite added (
vercel.jsonor_redirects) - [ ] Auth Site URL and Redirect URLs point to the live domain
- [ ] No
localhostleft in API calls - [ ]
npm run buildpasses locally - [ ] Import paths match file names exactly, including case
Still stuck?
These 5 cover most of the "works in preview, broken in production" problems I see, but AI-generated code can fail in creative ways. If your app still won't behave, drop your error in the comments and I'll try to point you in the right direction.
And if you'd rather have someone fix and deploy it for you, I do exactly that for apps built with Lovable, Bolt, Replit and Cursor: fix bugs · deploy with your domain.
Top comments (0)