MELLEPRISE MELLEPRISE MP Blog
← All articles

Lovable supabase saves work in preview but fail on the live URL

Pastel comic of a form being filled on the left screen and the same form empty on the right screen with a broken arrow between them

Your lovable supabase setup looked finished in preview, then the live site saved nothing and listed zero rows.

Preview felt solid. You filled a form, saw the row in the Table Editor, and assumed publish would behave the same. After deploy, the UI still submits. Toast messages may even say success. Open Supabase on the project you thought you were using and the table is empty. Or worse, data lands in a dev project while customers stare at an empty production database.

These failures cluster around three causes: preview and live talk to different Supabase projects, row level security blocks inserts without a policy, or reads hit the wrong schema. The editor connects Supabase during build. It does not verify that your hosting env vars, RLS policies, and project ref stayed aligned when the URL changed.

Saves in preview, empty on the live site

This is the most common lovable supabase symptom. You create a note, profile field, or order line in preview. Supabase Table Editor shows the row. You publish. The same form on the live URL submits without an obvious error, but the list stays blank and the dashboard shows no new rows.

What you might see:

  • Insert appears to succeed; refresh shows nothing
  • Data exists in Supabase, but only in a project named like dev or preview
  • Network tab returns 201 Created against one project ref and your live app reads another
  • SELECT returns [] because RLS hides rows from the anon role even though INSERT ran
  • Hard refresh on live still shows an empty state while preview on the Lovable URL still has data

Check the browser network tab on the live site. Find requests to *.supabase.co. Note the project ref in the hostname. Compare it to the ref in your Supabase dashboard URL. If they differ, your live bundle is not talking to the database you have been watching in preview.

Also compare keys. Lovable injects VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY for preview. Production reads whatever your host set. A stale anon key from an old project returns empty arrays or auth errors that React swallows behind optimistic UI.

Why lovable supabase preview and production diverge

Lovable generates the Supabase client against the environment visible during chat. That environment is the preview origin and the keys stored in the editor integration. Publish copies the frontend to Vercel, Netlify, or a custom domain. The build step on the host re-bundles with production env vars. If you never copied the Supabase URL and anon key to the host, the build may embed blanks, fall back to placeholders, or use keys from an earlier experiment.

AI assistants also spin up fresh Supabase projects quickly. One session links project A. A later session reconnects project B after a reset. Preview picks up the latest integration. Production still points at project A until you update hosting secrets manually. Both projects look fine in isolation. Your users only see the empty one.

Another pattern: preview uses the service role in server-side code during development while production uses the anon key in the browser. Service role bypasses row level security. Data appears in preview. Live anon requests hit RLS and return nothing. The fix is policies, not another prompt in the chat panel.

Missing insert policy blocks live saves

You enabled row level security because an article warned your database was public. Good. Inserts now fail with new row violates row-level security policy or fail silently when the client does not surface Postgres errors. Preview may still work if RLS was off in the dev project or if preview used a role that bypasses policies.

RLS defaults to deny. You need explicit policies per operation. A SELECT policy alone lets users read their rows but not create new ones. An INSERT policy must include a with check clause that ties new rows to auth.uid().

Typical fix for user-owned rows:

alter table public.items enable row level security;

create policy "Users read own items"
on public.items for select
using (auth.uid() = user_id);

create policy "Users insert own items"
on public.items for insert
with check (auth.uid() = user_id);

Common mistakes after enabling RLS on a lovable supabase app:

  • INSERT policy missing entirely
  • user_id not set on insert, so the policy check fails
  • Policy uses auth.uid() but the client inserts while logged out
  • Only the authenticated role is allowed; anon test calls fail as expected
  • Policies exist in the dashboard but were never added to migration files, so a redeploy from scratch wipes them

Test as a real logged-in user on the live URL, not only in the Table Editor with admin access. For the full picture on locking tables down, see supabase rls.

Two different Supabase projects

Split-brain is easy when one person connects Supabase inside Lovable and another copies env vars to Vercel from an older screenshot. Preview writes to project abcd1234. Production reads project wxyz9876. Each dashboard looks healthy. Your app never shows unified data.

Audit in four steps:

  1. Open Lovable project settings and note the Supabase URL and anon key used for preview.
  2. Open your hosting provider dashboard β†’ Environment Variables β†’ Production. Compare URL and anon key character for character.
  3. On the live site, open DevTools β†’ Network, trigger a save, and read the *.supabase.co hostname.
  4. In Supabase β†’ Project Settings β†’ General, confirm the project ref matches all three sources.

If anything differs, pick one production project and align everything to it. Update hosting env vars. Redeploy so the bundle picks up new values. Migrate any rows stuck in the wrong project or accept that preview test data was never production data.

Keep a single .env.example in the repo listing required keys without secret values. Document which Supabase project is production in your runbook, not only in chat history.

Fix lovable supabase before the next deploy

Work in this order so you do not chase UI bugs when the database layer is wrong.

  1. Confirm one Supabase project ref across Lovable preview settings, hosting production env, and live network requests.
  2. Copy VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY to production env on the host. Redeploy after changes.
  3. Inventory every table the app reads or writes. Enable RLS on tables with user or private data.
  4. Add SELECT, INSERT, UPDATE, and DELETE policies that match how the app behaves.
  5. Ensure inserts set user_id (or equivalent) before the policy runs.
  6. Log out on live, call the REST API with the anon key, and confirm you cannot list private rows.
  7. Log in on live, save a row, and confirm it appears in the correct project Table Editor.

Ship policy SQL in migration files under version control. Dashboard-only clicks drift between staging and production the same way env vars do.

Database wiring is one of five production settings AI editors rarely prompt for. Auth URLs, Stripe webhooks, env vars, and TLS fail on the same launch weekend. The lovable deploy checklist covers the rest so you are not debugging an empty table while login and payments are also miswired.

Pre-launch checklist

  • Same Supabase project ref in preview settings, production env, and live network traffic
  • Production anon key and URL redeployed after any Supabase project rotation
  • RLS enabled on every table that should not be world-readable
  • INSERT policy exists for every table users save to from the live app
  • user_id (or tenant key) set on insert before policy evaluation
  • Logged-out anon requests cannot read private rows
  • Policies committed in migrations, not only manual dashboard edits

Preview data is not production data until the same project, keys, and policies serve both URLs.

FAQ

Why does lovable supabase work in preview but show empty data live?

Preview and production often use different Supabase project URLs or anon keys. The live bundle may also hit tables with RLS enabled but no INSERT policy, so writes fail while the UI still looks fine.

How do I confirm Lovable and production use the same Supabase project?

Compare VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY in Lovable preview settings against your hosting provider production env vars. The project ref in the URL must match on both sides.

Do I need row level security policies for lovable supabase apps?

Yes, for any table with user data. Enable RLS and add SELECT and INSERT policies scoped to auth.uid(). Without an insert policy, authenticated saves return permission denied even though preview felt open.