If you're weighing a move from Firebase to Supabase, the SDK swap is the easy part. The hard part is that Firestore is a document database and Supabase is Postgres, so a migration is a data-model rewrite, not a lift-and-shift. Plan for three real problems — remodeling denormalized documents into relational tables, moving auth users without forcing password resets, and re-implementing realtime and security-rule logic under a completely different model. Everything else is tractable.
I've done this migration on two side projects and helped debug a third. Below are the questions that actually consume the timeline, with honest limitations on both sides.
Are Firebase and Supabase even the same kind of product?
They occupy the same slot in your stack — hosted backend with auth, database, storage, realtime, and serverless functions — but the databases underneath are fundamentally different, and that difference drives every migration decision.
| Concern | Firebase | Supabase |
|---|---|---|
| Primary database | Firestore (NoSQL, document) | Postgres (relational) |
| Query model | Document/collection, limited joins | Full SQL, joins, views, CTEs |
| Realtime | Firestore listeners (native) | Postgres changes via logical replication |
| Authorization | Security Rules (custom DSL) | Row Level Security (SQL policies) |
| Functions | Cloud Functions (Node, others) | Edge Functions (Deno/TypeScript) |
| Self-hostable | No | Yes (open source) |
| Vendor | Supabase (Postgres is portable) |
The single most important line in that table is the database row. In Firestore you design around your read patterns and duplicate data freely; in Postgres you normalize and let SQL do the joining at query time. You cannot copy documents into rows one-to-one and expect a good result.
Takeaway: this is a database paradigm change wearing the costume of a vendor switch.
How hard is migrating Firestore data to Postgres?
Harder than the tutorials suggest, because the work is modeling, not moving bytes. A Firestore export gives you nested JSON with subcollections and denormalized copies of the same entity scattered across documents. Landing that in Postgres means deciding, for each nested structure, whether it becomes a proper table with a foreign key or stays as a jsonb column.
A pragmatic middle path is to land the raw documents in a jsonb staging table first, then extract relational tables with SQL rather than trying to reshape everything in application code:
-- Stage the raw export, then normalize incrementally.createtablestaging_users(idtextprimarykey,docjsonbnotnull);-- Promote a clean relational table out of the staged JSON.insertintousers(id,email,display_name,created_at)selectid,doc->>'email',doc->>'displayName',to_timestamp((doc->>'createdAtSeconds')::bigint)fromstaging_userswheredoc->>'email'isnotnullonconflict(id)donothing;Keep jsonb for genuinely schemaless or rarely-queried blobs — Postgres indexes jsonb with GIN, so you don't have to normalize everything on day one. Normalize the entities you filter and join on; stage the rest.
What tripped me up: Firestore timestamps, references, and geopoints don't have clean Postgres equivalents, so your export parser needs explicit handling for each. Firestore document IDs are strings, and if you were relying on Firestore's auto-IDs as primary keys, keep them as text rather than trying to convert to integers mid-migration.
Takeaway: stage as jsonb, then normalize the hot entities with SQL — don't reshape everything in application code.
What happens to my users and their passwords?
This is where migrations quietly fail, because a naive approach forces every user to reset their password — an unacceptable outcome for a live product. Firebase Authentication hashes passwords with a modified scrypt using Firebase-specific parameters (signer key, salt separator, rounds, memory cost), and you can retrieve those parameters and the per-user hashes from the Firebase Admin tooling.
As of mid-2026, Supabase's auth layer (GoTrue) can accept externally-hashed passwords on import, and the community tooling for Firebase-scrypt has matured — but this is the step to prototype first, before you commit to a date. Export a handful of test users, import them, and confirm they can log in with their existing passwords. If that proof-of-concept works, the rest is bulk. If it doesn't, you're looking at a forced-reset flow, and you want to know that in week one, not week six.
The mechanical part looks like exporting users, then importing with hashes and metadata preserved:
# Export existing users (hashes included) from Firebase.
firebase auth:export users.json --project my-firebase-project
# users.json now contains passwordHash, salt, and the project's# scrypt parameters — feed these into your Supabase import script.Preserve the original user IDs during import. Every foreign key you migrate — orders, posts, comments — points at those IDs, and remapping them after the fact is a second migration you don't want.
Takeaway: prove the password-hash import on test users before you schedule anything — it's the make-or-break step.
Do Security Rules and realtime translate directly?
No, and budgeting zero time for this is the most common planning mistake. Firestore Security Rules are a purpose-built DSL evaluated per request; Supabase authorization is Postgres Row Level Security, written as SQL policies on tables. The concepts overlap — both gate access by authenticated user — but you rewrite every rule by hand, and the mental model differs.
A Firestore rule like "users can only read their own profile" becomes an RLS policy:
altertableprofilesenablerowlevelsecurity;createpolicy"read own profile"onprofilesforselectusing(auth.uid()=user_id);RLS is genuinely more powerful — you get the full expressiveness of SQL, joins to other tables, and reuse across every client — but it's also easier to lock yourself out of your own data if you enable RLS and forget to add policies. My rule of thumb: enable RLS on every table from the start and write the policies alongside the schema, never after.
Realtime is the other non-obvious rewrite. Firestore's listeners are baked into the query model; Supabase Realtime rides on Postgres logical replication and streams row-level changes, which is powerful but has different latency and ordering characteristics. Complex Firestore listeners with client-side query composition often become a mix of Realtime subscriptions plus regular queries. Re-test every live-updating view.
Takeaway: Security Rules and realtime don't port — they get rewritten, and RLS-without-policies will silently block your reads.
When is the migration actually worth it?
Migrate when you're feeling the constraints of a document database — you keep denormalizing to fake joins, your queries need real aggregation, or you want SQL, views, and a portable data layer you could self-host. Supabase's open-source, Postgres-standard core is the strongest reason: your data isn't locked to one vendor's proprietary format.
Stay on Firebase when your app is genuinely document-shaped, you lean on the mature mobile SDKs and offline persistence, or you're deep in the Google Cloud ecosystem. Firestore's offline support and battle-tested mobile clients are still ahead for app-first products, and "our current stack works and we have no query pain" is a completely valid reason not to migrate. Pricing models differ too — both bill on usage but along different axes (Firestore meters reads/writes/deletes; Supabase is closer to a hosted-Postgres compute-plus-usage model as of mid-2026) — so re-model your actual workload against each rather than assuming one is cheaper.
Takeaway: migrate for SQL power and portability, not because Supabase is trendier this year.
Bottom line
If your pain is "I need real relational queries and I don't want to be locked in," Supabase is the right destination and the migration cost is justified. If your app is document-shaped and mobile-first and simply works, Firebase is not something you should leave on principle. Whichever way you're leaning, do two proofs-of-concept before you schedule anything: a password-hash import on test users, and a re-implementation of your single most complex realtime view. Those two spikes tell you the real timeline better than any migration guide.


Top comments (0)