scribase
Migrate from hosted Postgres

Move your project in one run. Nobody resets a password.

Paste your project ref, database URL, and service key. Scribase plans the move, shows you exactly what will change, copies everything after you confirm, and then proves it: row counts and checksums for every table, policy parity, and a real sign-in with an account you control.

Four steps in the console: connect the source, review a dry run that writes nothing, run it, and read the verification report. Your place is saved if you close the tab; credentials never are.

What moves

Everything a hosted Postgres app runs on

Schema
Tables, types, functions, indexes, and extensions, applied in dependency order and linted for anything that weakens security.
Data
Every table in public, copied in resumable chunks. A crash costs one chunk, not the whole run.
Row level security
Every policy re-applied after the data lands, then compared one for one against the source.
Auth
auth.users with the same ids and bcrypt hashes, linked identities (Google, GitHub, Apple, and the rest), and TOTP factors.
Storage
Buckets and every object, with a SHA-256 check on each file after upload.

What stays the same

  • User ids, so every foreign key and every issued JWT subject still matches
  • Password hashes byte for byte, so existing passwords keep working
  • Authenticator app codes, because TOTP secrets move with the user
  • Your client code: change the URL and keys, nothing else

What you do by hand

  • Signing keys are never copied. New anon and service_role keys are issued, so the two projects never trust each other.
  • Edge function source is not readable from a hosted project, so functions move from your local checkout: add --functions-dir with your functions folder to the CLI import (the console wizard does not move functions yet).
  • User-defined secrets are listed by name for you to re-enter; their values are never read.
How it works

Plan, run, prove

  1. Step 1

    Plan it

    The dry run reads the source only. It prints the tables, rows, users, objects, and bytes that will move, plus every finding a human should see first, such as a policy that admits every row.

    scribase import supabase --project-ref abcdefghijklmnopqrst \
      --org acme --project app --env production \
      --connection-string "$SOURCE_DB_URL" --service-key "$SOURCE_SERVICE_KEY" --dry-run
  2. Step 2

    Run it

    Drop --dry-run. Schema, users, data, policies, and storage move in that order, each step idempotent so a resumed run never duplicates a row.

    scribase import supabase --project-ref abcdefghijklmnopqrst \
      --org acme --project app --env production \
      --connection-string "$SOURCE_DB_URL" --service-key "$SOURCE_SERVICE_KEY"
  3. Step 3

    Read the report

    The verdict is fail-closed: VERIFIED only when every table matches on row count and checksum, every policy is present, and the sign-in proof passes. Anything else is MISMATCH or UNVERIFIED, with the failing tables named.

  4. Step 4

    Switch the URL

    Point your client at your Scribase URL with the new anon key. Existing sessions sign in again once; passwords do not change.

    const client = createClient(process.env.SCRIBASE_URL!, process.env.SCRIBASE_ANON_KEY!);
The verification report

Old versus new, table by table

Every import ends with this. The verdict is VERIFIED only when every row count and checksum matches, every policy is present, and the sign-in proof passes. The numbers below are an example of the format.

Tablehosted Postgres rowsScribase rowsChecksum
public.profiles12,40812,408 match
public.orders88,21488,214 match
public.order_items240,977240,977 match
Also checked: RLS policy parity, auth user count, storage object count, and a sign-in with an account you control. Verdict: VERIFIED
Hosted migration

Want us to host it? Join the hosted Postgres waitlist.

The importer runs today on any Scribase you operate. Hosted Scribase opens by source, in waitlist order. Tell us your size and we will reach out when your slot opens.

FAQ

Migrating from hosted Postgres

Do my users have to reset their passwords?

No. The source stores bcrypt hashes in auth.users.encrypted_password. The importer copies them unchanged and keeps each user id, so the same email and password work on Scribase. The report can prove it with a live sign-in using an account you control.

My free project is paused. Can I still migrate?

Restore it from your current provider first, because a paused project refuses database connections. Then run the dry run straight away.

What does the verification report compare?

For every table: the source row count, the Scribase row count, and an order-independent checksum of every row on both sides. It also compares RLS policies, auth user counts, storage object counts, and runs the sign-in proof.

Is it safe to run twice?

Yes. Every write is an upsert keyed on the original ids, and the run resumes from a checkpoint after a failure.