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.
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.
| Phase | Time | Notes |
|---|---|---|
| Schema + row policies | 1.5 s | one migration |
| 610 users (bcrypt passwords kept) | 32 s | users sign in with their old passwords |
| 124,003 rows | 45 s | 189 requests; each batch of up to 200 statements is one transaction |
| 1,610 files (11.8 MiB) | 163 s | the slowest part today |
| Total | 4 min 2 s | every 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