ichibaseichibase

Migrate to ichibase

Move an existing app into ichibase — your database schema, your data, and your end-user accounts — from Supabase, a generic Postgres (any host), MongoDB, MongoDB Atlas, or Firebase (Firestore + Firebase Auth). A guided wizard in the dashboard plus the @ichibase/cli do the work. Migration is available on Pro and Business plans.

Where your data lands. SQL sources (Supabase / Postgres) import into Postgres. NoSQL sources (MongoDB / Atlas / Firestore) import into MongoDB 1:1, or into Postgres — where every document is scanned to build typed tables automatically (nested objects/arrays become jsonb). Pick the target in the wizard or with --target mongo|postgres. SQL → NoSQL is not supported.

Source support at a glance

Source→ Postgres→ MongoDBAccounts & passwords
SupabaseYes (1:1 schema + data)Built-in: auth.users (bcrypt carries over)
Postgres (any host)Yes (1:1 schema + data)Bring-your-own-users mapping
MongoDB / AtlasYes (inferred tables)Yes (1:1)Bring-your-own-users mapping
Firebase FirestoreYes (inferred tables)Yes (1:1)Firebase Auth export (scrypt carries over), or a users collection via bring-your-own-users

“Bring your own users” means accounts stored in an ordinary table/collection are mapped into ichibase Auth field-by-field — see migrating auth & passwords.

How it works

The CLI runs on your machine, against your source. It reads your data and writes an ichibase migration bundle — a folder containing your schema, your rows/documents, and your users. Your source credentials never leave your computer. You then push the bundle to your project: each part uploads straight to object storage and a background job imports it. Nothing is destructive on the source.

A bundle is just files you can inspect before pushing:

bundle/
├─ manifest.json        # source kind, target flavor, table/collection list
├─ schema.json          # Postgres: tables, columns, types, keys, indexes, FKs
├─ data/
│  ├─ <table>.ndjson    # one JSON row per line (Postgres target)
│  └─ mongo.archive     # native mongodump archive (Mongo 1:1 target)
└─ auth.ndjson          # users: id, email, tagged password hash, oauth links

Before you start

  • A Pro or Business project to import into. Its database flavor must match your chosen target — a Postgres target needs a Postgres-enabled project, a Mongo target a Mongo-enabled one. The wizard only offers targets your project actually has.
  • Node 18+ and the CLI: npm i -g @ichibase/cli.
  • For a Mongo 1:1 import, mongodump on your PATH (ships with the MongoDB Database Tools). Postgres targets need no extra tools.
  • An owner token to push (skip if you drop the folder into the dashboard). Create one under Account → API keys and export it as ICHIBASE_TOKEN.

1 · Extract a bundle

Pick the command for your source.

Supabase

Tables, data, and auth.users (passwords come across). Use the Session pooler connection string (Project Settings → Database → Connection string → Session pooler) — the direct db.<ref>.supabase.cohost is IPv6-only and won't resolve on most machines:

ichibase migrate supabase \
  --conn "postgresql://postgres.<ref>:PASSWORD@aws-0-<region>.pooler.supabase.com:5432/postgres" \
  --out ./bundle

Generic Postgres (any host)

Any reachable Postgres — RDS, Neon, Render, Cloud SQL, self-hosted. Schema + data come across; map accounts with the bring-your-own-users flags if they live in a table:

ichibase migrate postgres --conn "postgresql://user:pw@host:5432/dbname" --out ./bundle

MongoDB / Atlas

Collections + documents. Default --target mongo is a 1:1 import (needs mongodump on your PATH); --target postgres reads every document and infers typed tables instead:

ichibase migrate mongodb --conn "mongodb://user:pw@host:27017" --db myapp --out ./bundle
ichibase migrate atlas   --conn "mongodb+srv://user:pw@cluster.mongodb.net" --db myapp --target postgres --out ./bundle

Firebase

Firestore documents + Firebase Auth. See the Firebase guide for the service-account key and password-hash parameters:

ichibase migrate firebase --service-account ./service-account.json --target mongo --out ./bundle
Bring your own users (any source): if your accounts live in a regular table/collection (not Supabase auth.users or Firebase Auth), map them into ichibase Auth with --auth-table/--auth-collection plus --auth-email-field, --auth-pass-field and --auth-hash-scheme bcrypt|argon2|fbscrypt|plain|none. Full flag list in auth & passwords.

2 · Push it to your project

Two ways, same result:

  • Dashboard — open Database → Import / Migrate, choose your source and (for NoSQL) the target, then select the bundle folder. Parts upload to storage from your browser.
  • CLI — push the same folder headlessly:
ichibase migrate push --project <slug> --bundle ./bundle --token "$ICHIBASE_TOKEN"

Either way you get a live progress view and a final report. The job runs in phases:

PhaseWhat happens
validatingManifest + bundle integrity checks; target flavor confirmed.
schemaPostgres: tables, columns, keys, indexes created (FKs deferred).
dataRows (NDJSON) / documents (archive or per-collection) loaded.
authUsers imported with original IDs + tagged password hashes.
verifyingRow/document/user counts compared against the bundle; FKs added.

What gets migrated

  • Schema(Postgres): tables, columns & types, primary keys, unique constraints, indexes, and foreign keys — recreated in your project's public schema. For NoSQL → Postgres the schema is inferred from your documents.
  • Data: every row (Postgres) / document (Mongo). Postgres foreign keys are added after load so insert order doesn't matter; identity/serial sequences are reset.
  • Auth: users keep their original IDs and passwords — see how passwords migrate.

Troubleshooting

SymptomFix
Supabase connect hangs / ENOTFOUNDUse the Session pooler host, not db.<ref>.supabase.co (IPv6-only).
mongodump: command not foundInstall the MongoDB Database Tools, or use --target postgres (no mongodump needed).
Target rejected on pushYour project lacks that DB. Pick the other --target, or enable the engine on the project.
Migrated tables return nothing with the anon keyExpected — RLS is on with no policies. Add policies; see Differences & gotchas.
A user can’t log in after migratingPassword hash scheme/params were wrong or unsupported — that user uses “forgot password”.
Read the differences & gotchas before you go live — most importantly, imported Postgres tables have RLS enabled with no policies, so only your service key can read them until you add policies. An import is idempotent (truncate-and-reload per table/collection), so a failed run is safe to retry and never touches your source.