Guides

Moving to Berth

Bring your database and your users over from Railway, Neon, Supabase or Firebase. Users keep their ids, and bcrypt passwords keep working.

Any Postgres: Railway, Neon, Render, Heroku

If your data is in Postgres, one command copies it into a new Berth app. It runs pg_dump on your computer (install PostgreSQL client tools 15 or newer), keeps only the public schema, and restores it. Dumps up to 2 GB.

berth migrate postgres --db-url "postgres://user:pass@host:5432/db" --app my-new-app

Every table arrives secret-key only. Then set each table's policy, create keys, and point your app at Berth. Already have a dump? berth apps restore my-new-app backup.dump does the same with a file.

Supabase, with users and passwords

berth migrate supabase --db-url "postgresql://postgres:PASSWORD@db.PROJECT.supabase.co:5432/postgres" --app my-new-app

This copies the public schema and your users. It also makes Supabase's own pieces work, so the dump restores as is: extensions.uuid_generate_v4(), auth.uid(), auth.role() and auth.jwt(), and the anon and authenticated roles. Then it moves auth.users over:

  • User ids stay the same, so your user_id columns still point at the right people.
  • Passwords keep working: Supabase's bcrypt hashes are accepted, and each one is upgraded to Berth's own on that user's next sign-in.
  • raw_user_meta_data becomes the user's data, and raw_app_meta_data becomes their claims.

Supabase's RLS policies come along, but Berth's table policies decide access, so recreate each rule as a custom policy. Most translate directly: auth.uid() = user_id works as written. The longer walk-through is in Migrating from Supabase.

Firebase

Firebase has two parts to move: users and Firestore data.

# 1. Users: export with the Firebase CLI, then import.
firebase auth:export users.json --format=json --project my-project
berth migrate firebase-auth users.json --app my-app
# 2. Firestore: export each collection to JSON (one object per document, keyed by id), then import.
berth migrate firestore firestore.json --app my-app
  • Each Firebase user gets a stable Berth id made from their Firebase uid, and the uid is kept in their claims as firebase_uid. Custom claims come along too.
  • Firebase's password hashes use a Google-only scrypt variant, so passwords cannot move. Users sign in with an email code, Google or Apple, or reset their password once.
  • Each Firestore collection becomes a table with a doc_id text column (the Firestore document id) and a data jsonb column holding the document. Query fields with SQL (data->>'name'), or add real columns later.

The Firestore file is {"collection": {"docId": {...fields}}}, the shape most export tools produce.

Users from anywhere else

The import endpoint takes up to 5,000 users per call, from supabase, firebase or plain berth format, and skips emails that already exist.

curl -sS -X POST https://api.atberth.com/v1/apps/$APP/auth/users/import \
  -H "Authorization: Bearer $SECRET_KEY" -H "Content-Type: application/json" \
  -d '{"source":"berth","users":[{"email":"ana@example.com","password_hash":"$2b$10$...","email_verified":true,
       "data":{"name":"Ana"},"claims":{"roles":["admin"]}}]}'

bcrypt hashes ($2a$, $2b$, $2y$), from Auth0, Clerk exports or your own database, keep working. Other hash formats are dropped and those users sign in with a code.

After the move

  1. Set each table's policy, and allow the functions your app calls from the client (PUT /rpc/{fn}/access).
  2. Swap your client library for a Berth SDK, or call the HTTP API.
  3. Move files with berth storage upload, and cron or worker code to functions and jobs.
  4. Turn on bot blocking and per-app limits if your old host had a bot problem.