Validate the migration

Run end-to-end checks on your destination Supabase project after migration: row counts, a sample API read, an auth check, storage, and manual follow-ups.

Migration finishes when the last row is inserted, but you are not done until you have confirmed the destination behaves like the source. Run these checks against your own Supabase project before you point production traffic at it.

Row counts

Compare counts table by table. A mismatch means an insert batch was skipped or rejected — usually a foreign key violation or a duplicate key.

SELECT relname AS table, n_live_tup AS rows
FROM pg_stat_user_tables
WHERE schemaname = 'public'
ORDER BY relname;

n_live_tup is an estimate refreshed by autovacuum. For an exact number on a suspect table, run SELECT count(*) FROM public.your_table; on both source and destination and diff them.

A sample API read

The REST layer relies on RLS and the correct roles. Hit PostgREST with your destination anon key:

curl "https://<project-ref>.supabase.co/rest/v1/your_table?select=*&limit=1" \
  -H "apikey: $ANON_KEY" \
  -H "Authorization: Bearer $ANON_KEY"

An empty array with HTTP 200 usually means RLS is blocking the read, not that data is missing. Confirm with a service-role query. A 42P01 maps to relation does not exist — the table is in a schema PostgREST cannot see.

An auth check

Auth users are inserted directly into auth.users with their bcrypt hashes preserved, so a real login is the only honest test:

curl "https://<project-ref>.supabase.co/auth/v1/token?grant_type=password" \
  -H "apikey: $ANON_KEY" -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"<known-password>"}'

A returned JWT confirms the hash and identity rows carried over. 400 invalid_grant means the credential or the identity row is wrong.

A storage read

List objects and download one file:

curl "https://<project-ref>.supabase.co/storage/v1/object/public/<bucket>/<path>" \
  -H "apikey: $ANON_KEY" --output check.bin

Confirm the byte size matches the source object.

Manual follow-ups

Some things cannot be copied and are listed in your report:

  • Rotate secrets — API keys and DB passwords stored on the old project should be regenerated, not reused.
  • Re-add OAuth providers — Google, GitHub and similar client IDs/secrets are configured in the dashboard, not in the database.
  • Redeploy Edge Functions — function code and secrets do not travel with the schema.

If any check fails, see troubleshooting for the specific error and fix.

Edit this page on GitHubLast updated July 13, 2026