MongoDB to PostgreSQL: How to Move Your Data

Replicate MongoDB collections into PostgreSQL tables with Airbyte's CDC connectors. Prerequisites, sync modes, nested document handling, and volume limits.

Summarize with AI:

Moving data from MongoDB to PostgreSQL means translating flexible, nested documents into typed relational rows, then doing it again on a schedule without taking the source cluster down. A one-off mongoexport handles the first copy. It does not handle the second one, and it never captures deletes.

This guide covers the managed path: replicating MongoDB collections into Postgres tables with Airbyte's certified connectors, using change data capture. It also covers the constraints worth knowing before you start, because several of them will stop the pipeline at setup rather than at runtime.

MongoDB to PostgreSQL at a glance:

Replication methodChange data capture via MongoDB change streams, or full refresh
Source requirementMongoDB deployed as a replica set (Atlas or self-hosted), TLS enabled
Destination behaviourEach stream writes to one Postgres table
Handles deletesYes, in CDC mode
Practical volume ceilingAirbyte recommends Postgres destinations for roughly 10GB or less
Setup timeUnder an hour for a first connection

Why move data from MongoDB to PostgreSQL?

Two situations account for most of these pipelines.

The first is analytical. MongoDB is serving the application well, but the reporting layer, the BI tool, or the analyst team all speak SQL. Replicating collections into Postgres gives them joins, window functions, and a stable schema to build on, without adding read load to the operational cluster.

The second is a genuine migration. The application has outgrown a schemaless store and needs foreign keys and multi-table ACID guarantees. Here the pipeline runs alongside the old system during cutover, keeping Postgres current until traffic is switched. If you are still weighing the two databases, our MongoDB vs. PostgreSQL comparison covers the trade-offs in detail.

What do you need before you start?

The MongoDB source connector has hard prerequisites, and most failed setups trace back to one of them:

  • A replica set. Airbyte reads changes from MongoDB change streams, which only exist on a replica set. A standalone mongod will not work. On Atlas, this means a dedicated M10 tier or above, since shared tiers can fail during connection setup.
  • TLS/SSL. Required by the connector. It is on by default for Atlas clusters.
  • A user with readAnyDatabase. Since connector version 2.0.0, a single source can sync collections across multiple databases, and that expanded access needs the readAnyDatabase privilege. Without it, the connection fails with an authorization error.
  • A consistent _id type. Every document in a collection must use the same data type for _id. Mixed types are unsupported. Views, capped collections, and clustered collections are also excluded, as are empty collections.

On the Postgres side you need a user with write permission on the target schema, and for Airbyte Cloud an SSL or TLS connection, which is the default. If your organization restricts inbound traffic by IP, add the Airbyte Cloud IP addresses to the allow list on both databases.

How do you build a MongoDB to PostgreSQL pipeline in Airbyte?

Step 1: Create a read-only MongoDB user

In Atlas, add a database user under Security → Database Access with password authentication, give it the built-in "Only read any database" role, add the readAnyDatabase specific privilege, and restrict it to the clusters you intend to replicate. Self-hosted, create the equivalent user in mongosh and enable security.authorization in your config. The MongoDB source docs walk through both paths with screenshots.

Step 2: Configure the MongoDB source

Add a new MongoDB source in Airbyte and supply the cluster type, the connection string, the database names to sync, and the credentials from step 1. Airbyte tests the connection immediately.

One advanced setting deserves attention. Because collections are schemaless, Airbyte samples documents to infer fields: 10,000 by default, configurable between 1,000 and 100,000. That discovery step runs $sample aggregations against every collection in parallel, which can put real pressure on a production cluster with many collections or large documents. Consider pointing discovery at a secondary or a staging replica if your cluster is busy.

Step 3: Configure the PostgreSQL destination

Add a Postgres destination with the host, port, database name, default schema, and credentials. From version 3.0.0, the Postgres destination uses Direct Load architecture: records are written straight to final tables, with no intermediate raw tables. Each table carries your columns plus three Airbyte metadata columns: _airbyte_raw_id, _airbyte_extracted_at, and an _airbyte_meta JSONB column recording per-row typing changes.

If you have an existing Postgres destination on an older version, read the migration guide before upgrading. Downstream dbt models that reference raw tables or _airbyte_loaded_at will need updating.

Step 4: Choose sync modes and run

Create a connection, select your collections, and pick a sync mode per stream. Incremental with CDC keeps Postgres current and propagates deletes; full refresh re-reads a collection end to end and is checkpointed, so a network failure resumes rather than restarts. Set a replication frequency, save, and trigger the first sync. For a deeper look at change streams and resume tokens, see our MongoDB CDC guide.

How do nested MongoDB documents land in PostgreSQL?

This is the decision that shapes your downstream SQL.

In schema-enforced mode (the default), Airbyte samples documents, builds a field list, and lets you deselect fields you do not need. Top-level fields become typed Postgres columns. When a field's structure disagrees with the inferred schema, say a single object where an array was expected, the connector wraps it rather than writing NULL. That normalization is meant for occasional inconsistencies, not for fields that change type routinely.

In schemaless mode, every document produces a record with just _id and a data object holding the full document. Nothing is dropped and nothing is rejected, but unpacking happens in Postgres, using JSONB operators or dbt models downstream.

Pick enforced mode when collections are stable enough to model. Pick schemaless when they genuinely vary, and do the shaping in SQL.

When is PostgreSQL the wrong destination?

Airbyte's own documentation is direct about this: Postgres is an excellent relational database but it is not a data warehouse, and it recommends Postgres destinations for small volumes of roughly 10GB or less, or for testing. Beyond that, expect slowdowns on large writes, and watch memory, CPU, and IOPS during syncs. Postgres-compatible services such as Aurora are not exempt.

Two other limits are worth planning around. Postgres truncates identifiers at 63 bytes, so deeply nested collections flattened into long column names can collide and fail the sync. And during CDC, MongoDB's 16MB BSON document limit can surface as a BSONObjectTooLarge error when change events carry large documents; the MongoDB troubleshooting guide covers the fix.

If your MongoDB estate is larger than a few tens of gigabytes and the goal is analytics rather than an application migration, route the same source to a warehouse destination instead. The connector setup is identical.

Frequently asked questions

Can I replicate MongoDB to PostgreSQL in real time?

Not strictly in real time, but close. Airbyte uses MongoDB change streams to capture inserts, updates, and deletes incrementally, and you control how often the connection runs. Latency is a function of your sync frequency, not of re-scanning collections.

Do I need a MongoDB replica set?

Yes. The connector reads from change streams, which are only available on a replica set. Atlas clusters on the M10 dedicated tier or above qualify; shared tiers may fail at setup.

Are deletes propagated to PostgreSQL?

Yes, when the stream uses incremental CDC. Full refresh mode re-reads the collection instead and does not track individual deletions.

How are nested documents converted to Postgres columns?

In schema-enforced mode, Airbyte samples documents and maps top-level fields to typed columns. In schemaless mode, each record arrives as _id plus a data object, and you unpack it with JSONB queries in Postgres.

Can I do this without writing code?

Yes. The setup above is entirely UI-driven. If you would rather manage it as infrastructure, the Terraform quickstart provisions the same source, destination, and connection from configuration files.

Get your MongoDB data into PostgreSQL

You can have a MongoDB to PostgreSQL connection running before the end of the day, with CDC, schema handling, and deletes covered. Airbyte's connector catalog includes 600+ pre-built connectors, so the same source can fan out to a warehouse later without rebuilding anything.

Start syncing now →

Integrate with 600+ apps using Airbyte

Move data from 600+ sources into warehouses, lakes, and beyond. Set up pipelines in minutes with pre-built connectors and the Connector Builder.