Firestore collections
Each top-level collection becomes a table, upserted by document id. Every row also stores _path.
FireMigrate moves data both ways. Forward: Firestore, subcollections, Auth, and Storage metadata into ordinary PostgreSQL tables. Reverse: any Postgres tables back into Firestore. Nothing is written until you pass --write.
source path → table
01 — what is written
Each top-level collection becomes a table, upserted by document id. Every row also stores _path.
Every parent document is scanned. users/*/posts/*/comments becomes users__posts__comments, with _parent_id and _parent_path.
Users go to firebase_auth_users. Password hashes are stored and never printed. This is not a Supabase auth.users import.
Object name, size, content type, and checksum go to firebase_storage_objects. File bytes stay in Firebase.
A field missing from the sample is not dropped. It is kept in the jsonb column _extra.
tables prints JSON of every destination table, its source path, columns, and read/write hints.
02 — for agents
Run tables before an agent writes SQL. The manifest names every table, its Firebase source, parent table, columns, and a read/write hint. Do not invent table names.
$ npx @ezekielreu6/firemigrate tables
{
"version": 1,
"tableCount": 2,
"tables": [{
"table": "users__posts",
"sourcePath": "users/*/posts",
"kind": "subcollection",
"parentTable": "users",
"primaryKey": "id"
}]
}03 — commands
npx @ezekielreu6/firemigrate init
npx @ezekielreu6/firemigrate inspect
npx @ezekielreu6/firemigrate reverse
npx @ezekielreu6/firemigrate reverse --preview
npx @ezekielreu6/firemigrate migrate --dry-run01 init [--force]Creates firemigrate.config.json and .env.example. It never writes credentials, and it will not overwrite files unless you pass --force.
02 inspect [--sample=<n>]Read-only. Counts collections, walks every document for subcollections, summarizes Auth, and samples Storage metadata.
03 tablesPrints the agent JSON manifest. Stdout is JSON only. Call only the table names in that list.
04 schemaPrints the proposed PostgreSQL schema. Nothing is applied.
05 migrate --dry-runThe default. Streams every row and reports counts. Nothing is written.
06 migrate --writeCreates missing tables and upserts every streamed row. Also requires "dryRun": false in the config.
07 verifyCompares PostgreSQL row counts with the rows that were streamed. A mismatch exits non-zero.
08 reverseInspect any PostgreSQL tables and propose Firestore mappings. Works even if the tables were not created by FireMigrate.
09 reverse --previewSample a few rows and show the proposed Firestore documents.
10 reverse --writePush tables to Firestore. Requires Firebase credentials and "dryRun": false.
Skip a piece with --skip-auth, --skip-storage, or --skip-subcollections.
05 — reverse
The reverse command inspects any Postgres tables, proposes collection names and document ids, and can write them back to Firestore. It reuses _path when present and merges _extra. Available on the beta tag.
npx @ezekielreu6/firemigrate@beta reverse --preview04 — limits