BlogMongoDB

Leaving MongoDB for PostgreSQL JSONB, FerretDB or DocumentDB

Scott Sternloff

By Scott Sternloff, Senior Enterprise Architect

LinkedIn · Updated · 4 min read

Leaving MongoDB for PostgreSQL JSONB, FerretDB or DocumentDB
On this page

Moving off MongoDB is one of three projects: rewrite the data layer for PostgreSQL JSONB, keep the MongoDB drivers and put FerretDB or DocumentDB in front of PostgreSQL, or use Amazon DocumentDB as a managed API. Which one is safe depends on four things the application uses: aggregation pipelines, multi-document transactions, change streams and BSON types. Count those first, then choose.

This article is about leaving MongoDB. For version upgrades, Atlas moves and backups, read MongoDB migration: upgrades, Atlas moves and backups. For the wider choice, including staying put, see MongoDB alternatives compared, and for running MongoDB itself, AceMQ's MongoDB consulting and support page. Everything below follows vendor documentation checked on 4 November 2026.

Step 1: Inventory what the application really uses

Start in the code, not the cluster. A search for the features that other engines replicate worst takes minutes and sets the whole plan:

grep -rnE '\$lookup|\$facet|\$graphLookup|\$merge|\.watch\(|withTransaction|startSession' src/

Then list each collection with its document count, average and largest document size, indexes and write rate, and note which fields are ObjectId, Decimal128 or date values. The traffic matters more than the schema. Ten pipelines on a nightly report are a different job from ten on the checkout path.

What each finding means for the target
Finding in the codeConsequence
$lookup, $facet, $graphLookup pipelinesRewritten as SQL on PostgreSQL. On a proxy or Amazon DocumentDB, test each stage against the supported-operations list
withTransaction or multi-document writesNative in PostgreSQL. FerretDB's 2.7 documentation lists the transaction commands as unsupported, so it rules FerretDB out for that code
watch() on a collectionNeeds a replacement on PostgreSQL, such as logical decoding or a CDC tool. Amazon DocumentDB supports change streams
ObjectId, Decimal128, datesJSONB stores JSON, so decide a rule for each type before loading data
Large documents updated oftenAn update to a jsonb value locks the whole row, so hot fields become columns

Step 2: Choose the path from the findings

  • PostgreSQL JSONB when the findings are mostly plain reads and writes, a few joins and no change streams. You rewrite data access, and you get one engine with full transactions.
  • FerretDB or DocumentDB when the application code cannot change. FerretDB is Apache-2.0 and converts MongoDB 5.0+ wire protocol queries to SQL on PostgreSQL with the DocumentDB extension; DocumentDB is MIT licensed. FerretDB describes itself as a drop-in replacement in many cases, not all, so test DocumentDB the same way.
  • Amazon DocumentDB when the estate is AWS-only and wants the operations handled. AWS says it does not support every MongoDB feature and publishes the differences.
  • Stay on MongoDB when pipelines, change streams or sharding carry the application.

Step 3: Move the data

To PostgreSQL. AWS DMS reads MongoDB in document mode (one _doc column per document) or table mode (fields flattened to columns). Table mode needs consistent types per field, does not support documents nested deeper than 97 levels, and requires UTF-8 source data. AWS recommends an oplog that retains at least 24 hours of changes, because a task fails if the oplog rolls past it. A simple target keeps the document and promotes what you query:

CREATE TABLE orders (
  id  text PRIMARY KEY,
  doc jsonb NOT NULL,
  status text GENERATED ALWAYS AS (doc->>'status') STORED
);
CREATE INDEX orders_doc_gin ON orders USING GIN (doc jsonb_path_ops);
SELECT doc FROM orders WHERE doc @> '{"customer": {"tier": "gold"}}';

PostgreSQL's documentation says jsonb_path_ops supports only the containment and jsonpath operators but is usually smaller and faster for them than the default operator class, so pick the class from the queries you listed in step 1.

To FerretDB. Its documentation uses mongodump and mongorestore, or mongoexport and mongoimport per collection, and asks you to complete its pre-migration testing first. To Amazon DocumentDB. Use DMS in document mode or the same dump tools. Connect with a driver compatible with MongoDB 5.0 or later, and note that 5.0.1 and 8.0 require TLS 1.2 or higher. AWS lists new aggregation stages and a new query planner in 8.0, so test on the engine version you will actually run.

Step 4: Run both and compare before cutover

Keep MongoDB writable until the new store has passed three checks: document counts and checksums per collection, the recorded production queries replayed against both with results compared, and a rehearsed rollback. Move reads first, then writes, with one service at a time. The cutover is the last day of a plan, not the plan.

Where AceMQ fits

AceMQ turns the four steps into an inventory, a written recommendation (stay, proxy or leave), a parallel run and a cutover, then supports the result with 24/7 PostgreSQL support or MongoDB support. A typical engagement is described in MongoDB to PostgreSQL JSONB assessment, and database migration to PostgreSQL covers the wider method. AceMQ does not rewrite application code; that stays with your developers.

Sources

Frequently Asked Questions

Can AWS DMS migrate MongoDB to PostgreSQL?

Yes. AWS DMS supports MongoDB as a source in two modes. Document mode puts each document in a single _doc column, which suits a jsonb target. Table mode flattens top-level and nested fields into columns, and requires each field to keep one data type across a collection. Both modes read the oplog for ongoing changes, so size it to cover the copy.

Does FerretDB support multi-document transactions?

FerretDB's 2.7 documentation lists commitTransaction and abortTransaction as unsupported, so multi-document transactions are not available. Check the current documentation for your version, and test any code path that uses withTransaction before choosing it.

Should I keep each document in one jsonb column or split it into columns?

Usually both. Put identifiers, foreign keys and fields you filter or join on in ordinary columns, and keep the variable remainder in a jsonb column. PostgreSQL's documentation notes that any update locks the whole row, so hot fields in a large document are better as columns.

Scott Sternloff

Author

Scott SternloffSenior Enterprise Architect

Senior Enterprise Architect at AceMQ. Writes the technical coverage here: RabbitMQ, Kafka and Redis architecture, clustering and migrations.

Talk to an engineer

Need a hand with MongoDB?

Senior engineers who run it in production. Get a quote or a free consultation, no sales pitch.

Free Consultation

Get Expert Eyes on Your MongoDB Environment

Whether you're troubleshooting a production incident, planning a migration, or want a second opinion on your architecture — our team is ready. No pitch, just answers.

Email Us