Docs

Case study: a 124k-row Supabase import

A movie-ratings Supabase project — 124,003 rows, 610 users with passwords, 1,610 files and row-level security — moved with one command, timed and verified.

Updated Oct 24, 2026

We imported a Supabase project shaped like GroupLens' MovieLens ml-latest-small (movies, links, 100,836 ratings, tags; foreign keys to auth.users; 4 row policies using auth.uid(); 2 buckets with 1,610 files) with sov import supabase, into a local Sovaria stack of the real engines, and checked every row.

PhaseTimeNotes
Schema + row policies1.5 sone migration
610 users (bcrypt passwords kept)32 susers sign in with their old passwords
124,003 rows45 s189 requests; each batch of up to 200 statements is one transaction
1,610 files (11.8 MiB)163 sthe slowest part today
Total4 min 2 severy table's row count and checksum match the source

Writing this test changed the importer: data now loads in batches that are applied whole or not at all, so --resume continues exactly after the last committed batch (before, a failure in the middle of a batch could make a resume insert rows twice), and the data phase got 2.9× faster. Storage is copied 8 objects at a time (--storage-concurrency).

sov import supabase --db-url "$SUPABASE_DB_URL" \
  --supabase-url https://<ref>.supabase.co --service-key "$SUPABASE_SERVICE_ROLE_KEY"
# big projects: one part at a time, resumable
sov import supabase --db-url "$SUPABASE_DB_URL" --only data --resume