Guides

How to Migrate from Firebase to Supabase (Step-by-Step)

A practical migration guide based on real teams who moved production apps from Firebase to Supabase. Includes the 7-step dual-write method, timestamp conversion gotchas, and honest timelines.

By stacknocode Team

Most Firebase-to-Supabase migration guides read like marketing copy. This one is based on real teams who migrated production apps and documented what went wrong.

The primary source is Emergence Engineering, a team that migrated two production products (SzamlaBridge and PlaceOfCards) from Firestore to Supabase PostgreSQL in late 2024. They published their entire process, including the parts that broke. Additional insights come from developers on r/FlutterDev and r/Firebase who shared their migration experiences.


Why Teams Migrate

Before getting into the how, understand why — because if your reason does not match, you might not need to migrate.

Reason 1: NoSQL pain. Your data has outgrown Firestore. You are tired of duplicating data across collections and writing Cloud Functions to keep them in sync. Emergence Engineering described it perfectly: "In reality, NoSQL databases are great if you know your access patterns really well before building. For small teams seeking product-market fit, this is not a good deal — your data will change a lot, and 'sorry, we cannot query that' is not acceptable."

Reason 2: Pricing surprises. Your Firebase bill is growing faster than your revenue. Per-document-read billing punishes popular features. You want predictable costs.

Reason 3: Vendor lock-in anxiety. You want the ability to export your data and leave. Firestore uses a proprietary format. PostgreSQL uses SQL — the most portable data format in computing.

Reason 4: Query power. You need JOINs, full-text search, geospatial queries, or complex aggregations that Firestore cannot do natively.

If none of these apply to you, staying on Firebase is fine. Migration is not free — expect 2-4 weeks of engineering time for a medium-complexity app.


The 7-Step Migration Method

This is the dual-write method used by Emergence Engineering. It minimizes risk because both databases run in parallel during the transition.

Step 1: Audit Your Firebase Schema

Before writing any migration code, map your Firestore structure:

  • List every collection and subcollection
  • Document the relationships between collections
  • Identify all Cloud Functions that read/write data
  • Note any denormalized data (the same field stored in multiple places)

Emergence Engineering found that their Firestore structure had evolved organically over years, with data duplicated across collections without clear documentation. Expect the same.

Step 2: Design Your PostgreSQL Schema

This is the most important step. You are not just copying Firestore into PostgreSQL — you are designing a proper relational schema.

Firestore collections become PostgreSQL tables. Firestore documents become rows. But the key difference is how you handle relationships. Instead of duplicating data, you use foreign keys and JOINs.

Example transformation:

Firestore (denormalized):

  • orders collection: { userId, userName, userEmail, productId, productName, total, createdAt }
  • users collection: { name, email, ... }

PostgreSQL (normalized):

  • orders table: { id, user_id (FK), product_id (FK), total, created_at }
  • users table: { id, name, email, ... }
  • products table: { id, name, ... }

You query the data with JOINs instead of storing redundant copies.

Step 3: Set Up Supabase with Row Level Security

Create your Supabase project and set up Row Level Security (RLS) policies. RLS replaces Firestore Security Rules — and it is more powerful because it operates at the database level.

For each table, define policies for:

  • SELECT: Who can read this data?
  • INSERT: Who can create records?
  • UPDATE: Who can modify records?
  • DELETE: Who can remove records?

Common patterns:

  • Users can only read their own data: USING (auth.uid() = user_id)
  • Admins can read everything: USING (auth.jwt() ->> 'role' = 'admin')
  • Public read, authenticated write: USING (true) for SELECT, USING (auth.role() = 'authenticated') for INSERT

Step 4: Write the Migration Script

This is where it gets technical. The big gotchas:

Timestamp conversion. Firestore uses its own Timestamp object. PostgreSQL uses ISO strings. Nested objects containing Firestore Timestamps need recursive conversion. Emergence Engineering had to write a convertToTimestamp function that walks through nested objects and converts every Timestamp it finds.

ID format mismatch. Firestore uses string IDs. Supabase uses UUIDs. You need to decide: keep the Firestore string IDs in PostgreSQL (works, but you lose UUID benefits) or generate new UUIDs and maintain a mapping table.

Nested objects become JSONB. Firestore documents can have deeply nested objects. PostgreSQL handles this with JSONB columns. This works, but you lose the ability to query nested fields efficiently. Better to normalize them into separate tables with foreign keys.

Arrays. Firestore arrays become PostgreSQL arrays. Straightforward, but check if your queries rely on array-contains operations — these translate to PostgreSQL array operators.

Run the migration script with a --dry-run flag first. Check the output. Then run with --force when confident.

Step 5: Dual-Write Deployment

This is the safety net. For a transition period, your app writes to both Firebase and Supabase simultaneously.

  1. Deploy code that writes every create/update/delete to both databases
  2. Reads still come from Firebase (your source of truth)
  3. Monitor Supabase for data consistency
  4. Fix any discrepancies

This typically runs for 1-2 weeks. It costs more in Firebase writes (you are still paying for those), but it guarantees no data loss.

Step 6: Swap Reads to Supabase

Once both databases are in sync:

  1. Switch all read operations to Supabase
  2. Keep dual-writing as a safety measure
  3. Monitor for issues — query results should match exactly
  4. Fix any data inconsistencies

Step 7: Remove Firebase

After 1-2 weeks of reading from Supabase with no issues:

  1. Stop dual-writing
  2. Remove all Firebase SDK code
  3. Delete the Firebase project (or keep it as a backup)
  4. Celebrate. You now have a portable PostgreSQL database.

Migration Timeline: What to Expect

App SizeTypical Timeline
Small (< 5 collections, simple auth)1-2 weeks
Medium (5-15 collections, Cloud Functions, real-time)3-4 weeks
Large (15+ collections, complex RLS, multiple apps)4-8 weeks

These are working-time estimates from real migrations. A Flutter developer who migrated a marketplace app with 3 separate applications reported spending about a month on the full migration.


What Gets Better After Migration

Developers who completed the migration consistently report the same improvements:

"I no longer have to figure out how to duplicate data from one document to a dozen other collections." Data lives in one place and you query it with JOINs.

"I do not have to write dozens of Cloud Functions." PostgreSQL functions and triggers handle logic that required Cloud Functions on Firebase.

"Edge Functions are faster in every aspect." Cold starts, deployment, and execution are all snappier on Supabase.

"I do not worry about read statistics anymore." No more architecting your app around minimizing Firestore reads.


What Might Be Worse

Be honest about the trade-offs:

Auth integration takes more effort. Supabase auth with Next.js SSR is a documented pain point. The auth docs have been called "essentially worthless" by multiple developers. Budget time to get this right.

Real-time is more limited. 500 concurrent connections on Pro plan. If you have a collaborative app with heavy real-time needs, this could be a constraint.

No built-in offline sync. Firestore caches data locally. Supabase requires PowerSync ($49/mo) or manual offline handling.

You need to know SQL. Firebase lets you avoid thinking about database management. Supabase gives you PostgreSQL power, but you need to understand indexes, query planning, and connection pooling.


Is Migration Worth It?

If your app is still small and Firebase is working fine, stay. Migration costs engineering time with no immediate feature benefit.

Migrate when:

  • Your Firebase bill is growing faster than your user base
  • You find yourself writing complex Cloud Functions for things that would be simple SQL queries
  • You need features Firestore does not support (full-text search, geospatial, complex JOINs)
  • You are planning to scale significantly and want predictable costs

Do not migrate when:

  • Your app is in early prototype stage
  • Firebase is working well and your bill is manageable
  • Your team has no SQL experience and no time to learn
  • You rely heavily on Firebase-only features (FCM, Crashlytics, offline sync)
#firebase#supabase#migration#backend#postgresql

RELATED PLATFORMS

MORE ARTICLES