arrow_back Back to Blog
lovable cloudsupabasemigration

Lovable Cloud to Supabase Migration Checklist

·

Most Lovable Cloud to Supabase migration guides stop at “dump the database, restore it, change two env vars.” That part takes an afternoon. The bugs show up a week later, when a user taps “Continue with Google” and nothing happens.

So we built the checklist we wished existed, and then turned it into a free migration checker that reads your project’s GitHub repo and tells you what your specific app needs. This post is the reasoning behind it.

What actually lives in a Lovable Cloud project

Lovable syncs your project to GitHub, and the backend is all there if you know where to look. supabase/migrations/ has every schema change as a timestamped SQL file. supabase/functions/ has your edge functions, one folder each, plus a _shared folder if Lovable got organized. supabase/config.toml has the project ref and, more importantly, any function that runs with verify_jwt = false. And src/integrations/supabase/types.ts is the generated type file, which doubles as a list of every public table even when the migrations are incomplete.

That last part matters more than it sounds. Migrations drift. If someone ever changed a column from the Cloud UI and Lovable didn’t write a migration for it, your repo is lying to you about the schema. Before trusting the SQL files, compare them against a real pg_dump --schema-only of the Cloud database. It is the first thing we run on every migration.

The boring part (that still needs doing in order)

Extensions first. If a migration does create extension if not exists pg_trgm you’re fine, but plenty of projects lean on pg_cron and pg_net that were switched on from a dashboard and never written down. Then the schema, then functions and triggers, then data, in that order. Triggers on auth.users deserve special attention: the classic handle_new_user that creates a profiles row has to exist before the first signup on the new project, or you get users with no profile and a frontend that crashes on null.

Copy the auth schema too. People forget that users don’t live in public. Dump auth.users and auth.identities with their password hashes and your users log in with the same password on the new project. Skip it and every single user has to sign up again, which is a great way to lose half of them.

Storage is the annoying one. The Supabase dashboard can’t move files between projects in bulk, so you either script it against the storage API or point rclone at both projects’ S3 endpoints. Buckets have to be recreated with the same names and the same public or private setting, and the policies on storage.objects come along only if they were in a migration.

Three things that break after the switch

We ran the checker against three public Lovable Cloud repos while building it. All three call Lovable’s AI gateway. Two of the three sign users in with Google through Lovable’s own OAuth. That’s the pattern.

Google sign-in goes through Lovable

Newer Lovable projects ship a file at src/integrations/lovable/index.ts that imports createLovableAuth from @lovable.dev/cloud-auth-js. The login button calls lovable.auth.signInWithOAuth("google"), Lovable’s broker does the OAuth dance with Lovable’s Google client, and then hands your app a Supabase session.

Move the database to your own project and that broker has nothing to hand tokens to. You need your own OAuth client in Google Cloud Console, the provider enabled under Authentication in Supabase, the callback URL set to your new project, and the frontend switched to plain supabase.auth.signInWithOAuth. It’s maybe an hour of work. Finding out from a user that login is broken is worse.

The AI features go quiet

Edge functions that read LOVABLE_API_KEY and post to ai.gateway.lovable.dev only work inside Lovable Cloud. Off it, they fail on the first call. The fix is boring: pick a provider, get a key, set it with supabase secrets set, and change the URL and model name in the function. The trap is that nobody tests the “summarize this” button during a migration.

Signup emails never arrive

On a fresh Supabase project the built-in email service only sends to members of your own team. Everyone else gets Email address not authorized, and even for your team it’s limited to a couple of emails an hour. Lovable Cloud hides this because it handles email for you. Set up custom SMTP before you switch traffic. We use Resend because the DNS setup takes ten minutes, but Postmark is just as good.

The cron job nobody remembers

One of the repos we tested was a personal finance app that syncs bank data every night. The sync runs from pg_cron, which calls an edge function over HTTP with net.http_post, and that function has verify_jwt = false and checks a shared secret header instead. Perfectly reasonable design. But the cron job has the old project’s URL baked into the SQL. Restore it as-is on a new project and it keeps calling the old one every night, quietly, until the Cloud project is deleted and the sync just stops.

That’s the kind of thing a checklist exists for. Grep your migrations for cron.schedule and supabase.co before you call it done.

How the checker works (and where it’s dumb)

The migration checker runs in your browser. It pulls the file list from GitHub, downloads the migrations, functions and app code, and pattern-matches them. No database connection, no .env, nothing sent to us. It only works on public repos because it uses GitHub without logging in.

It parses SQL with regular expressions, not a real parser. That’s a trade-off we’d make again: it’s fast and has no dependencies, and Lovable’s generated SQL is very regular. It can’t see anything changed from the Cloud dashboard that never made it into a migration, and odd SQL formatting can slip past it. Treat its output as the checklist, not the audit.

If you’d rather hand the whole thing off, we do Lovable Cloud to Supabase migrations at a fixed price, and you keep building in Lovable afterwards.