How to Migrate from Lovable Cloud to Your Own Supabase (2026 Guide)

I migrated an entire Lovable Cloud project to my own Supabase in one session. Database, auth users with original passwords, storage, edge functions, frontend - everything. Here is how.

Category

Guide

Date

May 7, 2026

Reading time

8 min

Views

202

Share


Updated May 2026. This guide now reflects v3.0.0 of the migration skill, which includes 65 deterministic steps (up from 38), 12 real-world traps integrated as explicit steps, TanStack detection, auth.identities migration, custom functions/triggers, private bucket support, and comprehensive verification. There is also a claude.ai chat version for users who don't use Claude Code.

I migrated an entire Lovable Cloud project to my own Supabase in one session. Database schema, 216 rows of data, auth users with original passwords, 37 storage files, 12 edge functions, and 240 frontend files. Everything.

For a long time, we in the community were finding workarounds - edge function exports, REST API calls, manual schema recreation. They worked, but they had gaps. Passwords couldn't be exported. Schemas had to be rebuilt by hand. Storage was a pain. The Lovable MCP changes all of that - this is genuinely a life-changer for migrations.

Here is how.


Ready to migrate?

Paste this into Claude Code and replace the placeholders with your info:

https://github.com/CarolMonroe22/lovable-cloud-to-supabase-migration

I want to migrate my Lovable Cloud project to my own Supabase.

Here is what I have:
- Lovable project ID: [YOUR_PROJECT_ID]
- Lovable workspace ID: [YOUR_WORKSPACE_ID]
- Supabase organization: [YOUR_ORG_NAME or "I'll pick one"]

I need: schema, data, auth users with passwords, storage,
edge functions, and frontend code. Walk me through it.

Claude Code reads the skill from the repo and handles most of the migration for you. It will ask for your approval at key points, and you only need to do 2 things manually in the Lovable dashboard (connect Supabase and connect GitHub to the new project).

If you prefer to install the skill first:

npx skills add CarolMonroe22/lovable-cloud-to-supabase-migration

Once installed, the skill activates automatically whenever you ask about migrating from Lovable Cloud. It asks which level you want:

  • Guided - explains each step, confirms before proceeding (recommended for first time)
  • Standard - moves faster, confirms key decisions only
  • Express - asks for source and destination, runs everything

Not using Claude Code? There is a claude.ai chat version that runs directly from the browser. It covers the backend migration (schema, data, auth, storage, edge functions) but delegates the frontend code to Claude Code on the web or your local terminal. More about it here.

Need to connect the MCPs first? Follow the MCP setup guide.

The rest of this post explains what's happening under the hood so you understand the process, no matter your technical level.


Do You Actually Need to Migrate?

Before we get into the how, let's talk about the why. Lovable Cloud is a solid managed database. It works well for a lot of projects and there's no reason to migrate if it's meeting your needs.

Consider migrating when:

  • You need direct Supabase dashboard access for monitoring and management
  • You need custom email templates (Cloud sends from no-reply@auth.lovable.cloud)
  • You need staging and production environments with separate databases
  • You want full control of your infrastructure

If Cloud is working for you, there's no rush. But if you need more - now you know you can get there without losing anything.


What This Migration Involves

Here's the full picture. The migration has 9 phases and 65 steps. Most of it is automated through the MCPs - you just need to click twice in the Lovable dashboard.

1. Scan source

What happens

Read schema, data, auth users + identities, functions, triggers, sequences, indexes, storage, config.toml, tech stack

Key steps

19

2. Create destination

What happens

New Supabase project via MCP (defaults to us-west-1)

Key steps

5

3. Apply schema

What happens

Extensions, enums, tables, sequences with last_value, custom functions, triggers, indexes, RLS

Key steps

9

4. Auth users

What happens

Migrate with original password hashes AND identities

Key steps

3

5. Insert data

What happens

All tables in FK order, rewrite URLs in all text/jsonb columns

Key steps

5

6. Storage

What happens

Public and private buckets, files via edge function, URL rewrite

Key steps

6

7. Edge functions

What happens

Deploy with correct verify_jwt per function, report required secrets

Key steps

4

8. Frontend code

What happens

Detect tech stack, push via GitHub, rebuild in Lovable

Key steps

9

9. Verify

What happens

Compare 12 categories between source and destination, scan for old URL leaks

Key steps

5

Now let's walk through each one.


What You Need

Claude Code

What for

Runs the MCPs that make this possible

Cost

Pro $20/mo or Max

Lovable MCP

What for

Reads from your Lovable Cloud database

Cost

Free (connected via /mcp)

Supabase MCP

What for

Creates and configures your new Supabase

Cost

Free (auto-available in Claude Code)

GitHub CLI

What for

Pushes frontend code

Cost

Free

If you have Lovable Cloud, you're already paying for Lovable. The only potential extra cost is Claude Code ($20/mo) and a Supabase project ($0-10/mo depending on your plan).

Setup docs:


The Migration, Phase by Phase

Phase 1: Scan Your Lovable Cloud Database

This is where the Lovable MCP shines. Connect it via /mcp in Claude Code, then you can run SQL directly against your Cloud database. The skill scans everything it needs in one pass:

Tables

Query

information_schema.tables

Why

Know what you're migrating

Columns and types

Query

information_schema.columns

Why

Recreate exact schema

Foreign keys

Query

information_schema.table_constraints

Why

Get the relationships right

Custom enums

Query

pg_type + pg_enum

Why

Custom types need to be created first

RLS policies

Query

pg_policies

Why

Security rules must match

Custom functions

Query

pg_get_functiondef

Why

handle_new_user and other critical functions

Triggers

Query

information_schema.triggers

Why

Wire functions to tables

Sequences

Query

pg_sequences (with last_value)

Why

Prevent duplicate IDs after migration

Custom indexes

Query

pg_indexes

Why

Keep queries fast

All data

Query

SELECT * FROM each_table

Why

Your actual data

Auth users

Query

SELECT id, email, encrypted_password FROM auth.users

Why

Users WITH passwords

Auth identities

Query

SELECT * FROM auth.identities

Why

Session recovery and password reset

Storage buckets

Query

storage.buckets (with public flag)

Why

Know which are public vs private

Storage URLs

Query

Scan ALL text/jsonb columns for storage references

Why

URLs hide in unexpected places

Tech stack

Query

package.json from source repo

Why

Detect classic (Vite) vs modern (TanStack)

Edge function config

Query

supabase/config.toml

Why

Read verify_jwt per function

That auth.users query is the one that changes everything. You can read the actual bcrypt password hashes - which means users keep their exact same login credentials after migration. No password reset. No "please create a new account." That was previously considered impossible.

With the full scan done, the skill knows exactly what it's working with. Time to create the destination.


Phase 2: Create Your Supabase Project

Via the Supabase MCP:

  1. Pick your organization
  2. Confirm the cost
  3. Create the project (defaults to us-west-1 to avoid capacity issues)
  4. Wait for it to be active (takes a couple of minutes)

The MCP handles all of this. You'll get a project URL and anon key automatically. Now the destination is ready - let's build the schema.


Phase 3: Apply the Schema

This phase follows a strict order. Getting it wrong means FK violations and missing dependencies.

  1. Enable pg_net extension - needed for storage migration in Phase 6
  2. Create custom enums (CREATE TYPE)
  3. Create tables in FK order (parent tables before children)
  4. Create sequences with the correct last_value from the source (prevents duplicate IDs)
  5. Create custom functions - including handle_new_user (auto-creates profiles on signup)
  6. Create triggers - wire the functions to their tables
  7. Create custom indexes - keep queries performing as expected
  8. Enable RLS and apply all policies

If handle_new_user is missing, new user signups succeed but no profile gets created. The app crashes when it tries to load profile data. This was one of the 12 traps we discovered during testing.

Schema is ready. Before we can insert data, we need the users in place.


Phase 4: Migrate Auth Users

This goes BEFORE your data. Why? Because your profiles table probably has a foreign key to auth.users. If you insert profiles first, the FK breaks.

INSERT INTO auth.users (
  id, instance_id, email, encrypted_password,
  email_confirmed_at, raw_user_meta_data,
  created_at, updated_at, role, aud
) VALUES (
  '{original_id}',
  '00000000-0000-0000-0000-000000000000',
  '{email}',
  '{original_bcrypt_hash}',  -- the EXACT hash, not a new password
  now(),
  '{metadata}'::jsonb,
  '{original_created_at}',
  now(),
  'authenticated',
  'authenticated'
);

Copy the bcrypt hash exactly as-is. Never generate temporary passwords.

You also need to migrate auth.identities alongside users. Without it, login works but password recovery fails, session refresh tokens break, and OAuth users can't re-link their accounts. Each user typically has one identity row with provider = 'email'.

Optional: If you want existing sessions to remain valid (no forced re-login), copy the JWT secret from the source dashboard to the destination. Settings > API > JWT Secret. There's no API for this - it has to be done manually.

Users are in place. Now the data can go in safely.


Phase 5: Insert Your Data

Order matters here too:

  1. Catalog/reference tables first - products, categories, types (things without user FKs)
  2. User-owned tables - profiles, brands, campaigns
  3. Junction/relation tables - campaign_products, campaign_experiences, etc.

Since auth.users already exist from Phase 4, the profiles FK works naturally. No need to drop constraints or do workarounds.

URL rewriting: After inserting data, the skill scans ALL text and jsonb columns for references to the old Supabase project ref and rewrites them. Not just columns named *_url or *_image - URLs hide in JSONB metadata fields, config columns, and text arrays. Missing these means broken images even though the files were migrated correctly.

Data is in. Next up: the actual files.


Phase 6: Migrate Storage

  1. Create buckets in the new Supabase, matching the original visibility (public or private)
  2. Deploy a temporary edge function that downloads files and uploads to new storage
  3. For private buckets, generate signed URLs from the source database instead of using public URLs
  4. Rewrite URLs in the database

The skill handles both public and private buckets. In v2, private buckets were silently skipped - the download returned 400 and files appeared migrated but were actually missing.

Files are moved. Now let's bring the backend logic over.


Phase 7: Deploy Edge Functions

For each function:

  1. Read the source code from the GitHub repo
  2. Read the verify_jwt setting from config.toml (saved in Phase 1)
  3. Deploy with the correct verify_jwt per function

This matters more than you'd think. Webhooks (Stripe, custom integrations) need verify_jwt = false. If deployed with verify_jwt = true, they reject every incoming request with 401. The reverse is also a problem - user-facing functions with verify_jwt = false become anonymously callable.

After deployment, the skill reports which secrets each function needs. Things like LOVABLE_API_KEY, OPENAI_API_KEY, STRIPE_SECRET_KEY. You set these manually in the Supabase dashboard (Settings > Edge Functions > Secrets). Functions will fail at runtime until the secrets are configured.

Backend is fully migrated. The last big piece is the frontend.


Phase 8: Move the Frontend Code

This is the part that took the most trial and error. Here's what I learned:

  • Remix doesn't work - it copies the project BUT inherits Lovable Cloud. Can't disconnect it.
  • GitHub integration is one-way... mostly - Lovable pushes to GitHub, but won't pull from it. Except it actually does pick up commits pushed from outside.

TanStack detection. Lovable changed its default project template to TanStack Start on May 6, 2026. The skill reads package.json from the source to detect whether it's classic (Vite) or modern (TanStack) and creates the destination project with the correct tech_stack. If the wrong stack is used, the git push succeeds but Lovable can't build it.

The working approach:

  1. Detect tech stack from source package.json
  2. Create a new empty Lovable project with the correct tech_stack
  3. Connect your Supabase (manual - dashboard click)
  4. Connect GitHub (manual - dashboard click)
  5. Clone the original project's GitHub repo locally
  6. Copy all files to the new repo and push
  7. Lovable picks up the commit
  8. Tell the agent to rebuild

Those 2 dashboard clicks are the only manual steps in the entire migration. Once the rebuild finishes, there's one thing left to do.


Phase 9: Verify

This phase is critical. Don't skip it.

The skill runs a comprehensive audit comparing 12 categories between source and destination:

Category           Source  Destination  Status
tables             N       N            OK
enums              N       N            OK
rls_policies       N       N            OK
functions_custom   N       N            OK or MISSING
triggers           N       N            OK or MISSING
sequences          N       N            OK or MISSING
indexes_custom     N       N            OK or MISSING
auth_users         N       N            OK
auth_identities    N       N            OK or MISSING
storage_buckets    N       N            OK
storage_objects    N       N            OK or PARTIAL
old_ref_leaks      0       0            OK

If anything shows MISSING or PARTIAL, the skill tells you exactly which phase and step to re-run. Then test login with original credentials to confirm the full auth flow works.


12 Traps (So You Don't Have To)

During testing, I found 12 things that cause silent failures during migration. Each one is now an explicit step in the skill, but here's the summary so you know what to watch for:

Wrong tech_stack on create_project

What happens if missed

Lovable can't build after git push

Severity

Critical

us-east-1 capacity outage

What happens if missed

Project creation fails

Severity

Degradation

pg_net not enabled

What happens if missed

Storage migration fails

Severity

Degradation

Private buckets assumed public

What happens if missed

Files silently missing

Severity

Silent bug

verify_jwt not read per function

What happens if missed

Webhooks 401 or security hole

Severity

Silent bug

Edge function secrets not listed

What happens if missed

Functions fail at runtime

Severity

Silent bug

URLs in JSONB not rewritten

What happens if missed

Broken images

Severity

Silent bug

Custom functions not migrated

What happens if missed

New signups break (no profile)

Severity

Critical

Sequences reset to 1

What happens if missed

Duplicate IDs

Severity

Critical

Custom indexes not recreated

What happens if missed

Slow queries

Severity

Degradation

auth.identities not migrated

What happens if missed

Password recovery fails

Severity

Critical

Verification only counts tables

What happens if missed

Missing pieces go unnoticed

Severity

Silent bug

Full details with fixes in trampas.md on GitHub.


The Numbers

For my test migration, here's what the final audit looked like:

Tables

Migrated

13

Custom enums

Migrated

5

RLS policies

Migrated

41

Custom functions

Migrated

4 (including handle_new_user)

Triggers

Migrated

3

Sequences

Migrated

1 (order_number_seq)

Custom indexes

Migrated

6

Data rows

Migrated

216

Auth users

Migrated

4 (with original passwords)

Auth identities

Migrated

4

Storage files

Migrated

37

Edge functions

Migrated

12 (with correct verify_jwt)

Frontend files

Migrated

240

Old URLs remaining

Migrated

0

Manual steps

Migrated

2

Everything else was automated via the MCPs. Zero data loss. Zero broken URLs. Users can log in with their original credentials.


After Migration: What to Watch For

A few things to keep in mind once you're migrated:

  • If your project uses Google OAuth, you'll need to update the redirect URL in Google Console to point to your new Supabase project. Otherwise users will get a 403 when trying to log in with Google.
  • Storage files from the old project will stop working if the original Lovable Cloud project is deleted. Make sure all URLs are rewritten before that happens.
  • Edge function secrets need to be configured in the new project's dashboard. The skill gives you the full list per function after Phase 7.

Resources

Enjoyed this?

Carol Ships: building, shipping, figuring it out.

Have another workaround to share?

Start the thread below!

Comments

No comments yet. Be the first to share your thoughts!