---
title: Firestore to PostgreSQL Migration: A Practical Guide | Remqa
url: https://remqa.com/blog/firestore-to-postgresql-migration
updated: 2026-11-11
---

[Home](https://remqa.com/) / [Blog](https://remqa.com/blog) / Firestore to PostgreSQL Migration: A Practical Guide

Migration guide

# Firestore to PostgreSQL migration: documents, subcollections, and cutover

Plan a Firestore to PostgreSQL migration with subcollection coverage, preserved document paths, explicit type mapping, and a tested application cutover.

Remqa · November 11, 2026 · 5 min read

**Short answer:** To migrate Firestore to PostgreSQL, inventory collection groups and full document paths, choose an extraction route, and define explicit mappings for nested data and Firestore types. Load a repeatable staging dataset, reconcile records and relationships, then switch application writes only after testing the target behavior. A managed Firestore export is not a ready-to-load PostgreSQL dataset or a complete application migration.

- Inventory subcollections separately when exporting selected collection groups
- Preserve full document paths rather than only final document IDs
- Use explicit conversions for references, timestamps, and special numeric values
- Treat application authorization and the write cutover as separate migration work

By the Remqa engineering team · Last updated November 11, 2026

Your PostgreSQL row count matches the number of customer documents, but the application opens an empty order history. The extraction copied the parent collection and missed its subcollections. A second problem appears when two documents with the same final ID overwrite each other. Firestore to PostgreSQL migration needs an identity and coverage plan before it needs an import script.

This guide combines documented extraction boundaries with recommended engineering controls. The staging layout, validation checks, and cutover process below are proposed migration design. They are not a promise that a vendor tool automatically preserves every application behavior.

## Inventory collection groups and application dependencies

List the database, each collection group, its document paths, its parent relationships, and the application screens that use it. Include nested collections, rarely used configuration, historical records, and background jobs. A list of the largest top-level collections is not a complete scope.

For each group, record representative field shapes and every type actually present. Separate absent fields from explicit nulls. Note arrays whose order matters, references to other documents, and fields whose type varies across records. Include records from older application versions rather than sampling only recently created documents.

Keep authentication, files, scheduled work, and application authorization on a separate dependency list. Moving database records does not establish that those systems have moved. If the application also needs changes, combine the data plan with a defined [code migration](https://remqa.com/code-migration) scope.

## Choose an extraction route deliberately

Firestore’s managed export service copies documents to files in Cloud Storage. An ordinary export is not an exact snapshot at its start time and may include changes made while it runs. Do not label it a consistent cutover baseline without addressing that boundary.

When exporting selected collection groups, explicitly include every group required by the migration. A collection group includes collections and subcollections with the specified final collection ID. Selecting a parent group does not automatically export its differently named subcollections. Verify the actual selection against your inventory.

Firestore also documents export from a point-in-time recovery timestamp with prerequisites and timestamp restrictions. If you choose that route, validate the database’s PITR configuration and the selected timestamp before building a downstream plan around it. A snapshot still needs a plan for writes that happen afterward.

An alternative is an application-level extraction. Supabase documents tools that dump a single Firestore collection to JSON and import it into a Postgres table. Its guide describes flattening into text, numeric, boolean, or jsonb columns and custom hooks for splitting data into related tables. That is a separate route from managed export. Test the exact tool against your data instead of assuming either route produces the same files.

> **Choose the converter before the final export.** Prove that it can read the chosen extraction format and preserve your required types and document paths. A successful export job only proves that the export completed.

## Preserve complete document identity

Use the source project, database, and full document path as the migration identity. Do not rely on a final document ID being globally unique. Two different parent paths can legitimately end in the same ID. Keep the original identity even if the target uses a new numeric or UUID primary key.

A practical staging design stores source identity, collection group, parent path, extraction batch, conversion version, and the preserved typed payload. Keep raw extraction files separately in restricted storage. A typed JSON representation is useful only when its encoding rules are explicit and tested.

Build an identity map from source paths to target keys. Use that map when turning references or parent-child paths into relationships. If a reference cannot be resolved, preserve it as an unresolved item for review. Do not silently create a substitute parent or drop the link.

## Map Firestore values before loading tables

Firestore supports more than ordinary JSON values. Its documented types include references, bytes, geographical points, timestamps, integers, floating-point numbers, arrays, and maps. Inventory the edition-specific types too if your database uses them. The table below is a starting design, not an automatic conversion specification.

| Source shape | Proposed target treatment | Required check |
| --- | --- | --- |
| Document reference | Preserved path plus mapped relationship | Correct source database and target record |
| Timestamp | Explicit timestamp conversion | Precision and application display behavior |
| Nested map | JSONB or a related table | Missing fields and explicit nulls remain distinct |
| Ordered array | JSONB array or child rows with position | Order and duplicate elements survive |
| Bytes or geographical point | Deliberate typed representation | Round-trip values and application use |
| Special floating-point value | Tagged representation or approved target policy | No silent conversion to null or a string |

PostgreSQL JSONB does not preserve object key order or duplicate object keys. Its JSON number input excludes NaN and infinity, and JSON null differs from SQL NULL. Firestore supports special floating-point values, so a generic JSON conversion can lose meaning. Define the exception policy before the full load and reject records that violate it.

## Make repeated loads measurable

Load into an isolated target first. Identify records by the preserved source identity so that a repeated batch updates the intended staging record rather than creating a duplicate. Record rejected rows with their source paths and reasons. Keep enough information to reproduce each conversion without putting private document contents into general logs.

Reconcile counts by collection group and parent path, not just across the whole database. Check unresolved references, duplicate target identities, null distributions, and rejected type conversions. Compare meaningful business totals where the data supports them. Explain every exclusion and every deliberate transformation.

Then run application checks. Open a parent record and its nested history. Verify ordered items, searches, edits, deletes, and permission boundaries. Have an operator inspect records they recognize. A matching count cannot prove that a screen reads the correct relationships.

## Plan the final write boundary and rollback

For a straightforward migration, choose a controlled write pause and a final extraction that can be reconciled before reopening writes on PostgreSQL. If the business cannot pause writes, design a separate change-capture and replay process, including deletes and ordering. Do not describe repeated exports alone as proven continuous synchronization.

1. Rehearse the extraction, conversion, and load with the same configuration intended for cutover.
2. Confirm which application and background processes can still write.
3. Establish the final source boundary and reconcile the target dataset.
4. Switch application configuration and test critical reads and writes.
5. Monitor rejected operations, missing relationships, and authorization failures.
6. Keep a rollback decision owner and a plan for target-only writes before restoring the old application path.

Keep the source available for controlled reference until the team accepts the migration. An old database is not automatically a safe rollback after PostgreSQL has accepted new writes. Decide how those writes would be preserved or reconciled before calling the cutover reversible.

## How Remqa can help

Remqa works on [data migrations](https://remqa.com/data-migration) that include extraction, mapping, application checks, and cutover planning. Bring a sample of your collection hierarchy and the screens that depend on it. An engineer can help define the scope, identify risky conversions, and build a tested path to PostgreSQL. Explore our [migration services](https://remqa.com/migrations) to start with the boundary your team needs to move.

## Questions people ask.

**Q: Can PostgreSQL directly load a managed Firestore export?**
Do not treat the managed export as a PostgreSQL import file. Plan a tested conversion route. Supabase documents a separate collection-to-JSON and JSON-to-Postgres workflow, which is different from the managed Firestore export service.

**Q: Does exporting a Firestore collection include its subcollections?**
When exporting selected collection groups, selecting a parent collection group does not automatically include its subcollections. List each required collection group explicitly and verify coverage against your inventory.

**Q: Should Firestore document IDs become PostgreSQL primary keys?**
Preserve the complete source identity first. A final document ID may be reused at different paths. Use a full path or a mapped target key with a unique source-path constraint, then rebuild relationships from that map.

**Q: Can all Firestore values be stored unchanged as JSONB?**
No. Firestore includes types such as references, timestamps, bytes, and special floating-point values that need deliberate encoding. PostgreSQL JSONB rejects NaN and infinity as JSON numbers. Define and test the conversion for each type present.

**Q: Does migrating Firestore data also migrate Firebase authentication and files?**
Treat those as separate workstreams. This data migration plan does not establish that authentication users, stored files, application authorization, or real-time behavior have moved. Include each required service in an explicit application migration inventory.

Book a free 30-minute call with an engineer: https://calendly.com/meghanaj-connect/30min
