Lovable app works in preview but breaks after deploy? Seven fixes
Login loops, blank pages, 404 on refresh, data that never loads. The most common reasons a Lovable or Bolt app breaks once it leaves the preview, and how to fix each one.
Everything works in the Lovable preview. You deploy it to your own domain on Vercel or Netlify, and suddenly login loops, pages go blank or the data never shows up.
The app is almost never "broken". Something that the preview handled for you is missing in production. Here are the seven causes I see most often, in the order I check them.
1. Supabase still redirects to localhost or the preview URL
Symptom: you log in, and you land on localhost:3000 or the old preview link, or you end up back on the login page.
Fix: in Supabase go to Authentication → URL Configuration.
- Site URL: your real domain, for example
https://myapp.com - Redirect URLs: add
https://myapp.com/**(and your Vercel preview domain if you use it)
If you use Google or GitHub login, the provider's own console needs the Supabase callback URL too: https://<project>.supabase.co/auth/v1/callback.
2. Environment variables are missing on the host
Symptom: blank page, or errors like supabaseUrl is required in the browser console.
Lovable keeps your keys in the project. Vercel and Netlify do not know them. Add them in the host's settings:
VITE_SUPABASE_URL=https://xxxx.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=...
Then redeploy. Variables are baked in at build time, so changing them without a new build does nothing.
3. Refreshing a page gives a 404
Symptom: the home page works, but refreshing /dashboard or opening it from a link shows "404 Not Found".
Lovable apps are single page apps: there is only one real index.html. Tell the host to send every route to it.
Vercel, vercel.json in the project root:
{ "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }] }
Netlify, a file public/_redirects:
/* /index.html 200
4. RLS blocks the data in production
Symptom: the page loads but lists are empty, or saving fails with new row violates row-level security policy.
In the preview you might have been testing as a different user, or with policies that changed since. Check that every table your app reads has a select policy for logged in users and every table it writes has a matching insert or update policy. I wrote a separate guide on the six causes of RLS insert errors.
5. The service role key ended up in the frontend
Symptom: everything works, which is the dangerous part.
If your code creates the Supabase client with the service_role key, anyone can open the network tab, copy it and read or delete your whole database. Search your code for service_role. In the browser only the publishable (anon) key belongs. Anything that needs full access moves to an Edge Function.
6. Stripe works in test mode only
Symptom: checkout opens, payment succeeds, but the user never gets access.
Usually the webhook is still pointing at the test endpoint or uses the test signing secret. In Stripe switch to live mode, create the webhook for your production URL, and put the live STRIPE_WEBHOOK_SECRET into your function's secrets.
7. Emails go nowhere
Symptom: sign up works but the confirmation email never arrives.
Supabase's built in email is rate limited and meant for testing. For real users, connect your own SMTP (Resend, Postmark, SendGrid) under Authentication → SMTP Settings, and add the DNS records your provider asks for so emails do not land in spam.
Still stuck?
Open the browser console (F12) and the network tab, reproduce the problem and read the first red error. Nine times out of ten it names the cause. If it does not, or you would rather not spend the weekend on it, this is the kind of fix I do: fixed price up front, usually done in 48 hours.