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.
| Finding in the code | Consequence |
|---|---|
| $lookup, $facet, $graphLookup pipelines | Rewritten as SQL on PostgreSQL. On a proxy or Amazon DocumentDB, test each stage against the supported-operations list |
| withTransaction or multi-document writes | Native in PostgreSQL. FerretDB's 2.7 documentation lists the transaction commands as unsupported, so it rules FerretDB out for that code |
| watch() on a collection | Needs a replacement on PostgreSQL, such as logical decoding or a CDC tool. Amazon DocumentDB supports change streams |
| ObjectId, Decimal128, dates | JSONB stores JSON, so decide a rule for each type before loading data |
| Large documents updated often | An 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
- Using MongoDB as a source for AWS DMS, AWS documentation.
- Amazon DocumentDB compatibility with MongoDB, AWS documentation.
- FerretDB migration documentation and repository.
- DocumentDB repository.
- JSON types, PostgreSQL documentation.
All read on 4 November 2026.
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.
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.
Guides, comparisons and research

