Migration wizard

Pick what to migrate. unbase generates your config and the exact commands to run locally. Your secrets never leave your machine — you fill the generated .env yourself.

1. What to migrate
Toggle the phases you need.
Schema-aware, FK-safe row load into your target Postgres.
Users + OAuth identities into Better Auth, bcrypt preserved.
Mirror storage objects and rewrite their URLs in your data.
Download object bytes during extract (off = list + reconcile only).
2. Details
3. env
# Source database
SUPABASE_DB_URL=""

# Service role key
SUPABASE_SERVICE_KEY=""

# Optional source URL
# SUPABASE_URL=""

# Target database
TARGET_DB_URL=""

# Target storage (Cloudflare R2)
STORAGE_ACCESS_KEY_ID=""
STORAGE_SECRET_ACCESS_KEY=""
STORAGE_BUCKET=""

# Cloudflare account ID
STORAGE_ACCOUNT_ID=""

# Public URL
STORAGE_PUBLIC_URL=""
4. Run, in order
npx unbase extract --mirror
npx unbase storage
npx unbase rewrite
npx unbase load
npx unbase auth
5. Better Auth password config
// Better Auth: verify migrated Supabase bcrypt hashes (no resets)
import bcrypt from "bcryptjs";

emailAndPassword: {
  enabled: true,
  password: {
    hash: (password) => bcrypt.hash(password, 10),
    verify: ({ hash, password }) =>
      /^\$2[aby]\$/.test(hash) ? bcrypt.compare(password, hash) : Promise.resolve(false),
  },
},