Your tenants want a MongoDB connection string. You run your entire stateful layer on CloudNativePG and have zero interest in operating a second database stack. FerretDB v2 says you can have both — a Mongo-wire-compatible endpoint backed by the Postgres fleet you already run.
That promise is real, but it has exactly one load-bearing prerequisite: the Postgres behind it must carry Microsoft's DocumentDB extension. On CloudNativePG that means a different container image, three shared preload libraries, one postInitSQL line, and a stateless FerretDB Deployment wired up with FERRETDB_POSTGRESQL_URL.
Everything else in this post is the receipt for that sentence: why v2 needs what v1 didn't, the concrete recipe, what it buys your ops team, and the honest gaps to verify before you tell anyone to "just point your Mongo driver here."
Why v2 needs DocumentDB and v1 didn't
FerretDB 1.x did something heroic and slow: it accepted MongoDB wire-protocol traffic and translated every operation into SQL against plain, unmodified PostgreSQL. No extension, no custom image — any Postgres would do. The cost was a translation layer that had to emulate document semantics (nested BSON, flexible indexing, aggregation pipelines) on a relational engine that had no native notion of them.
FerretDB 2.0, generally available since March 2025, deleted most of that problem by moving it into Postgres itself. The vehicle is DocumentDB: two MIT-licensed PostgreSQL extensions Microsoft open-sourced in January 2025 — pg_documentdb_core, which adds a native BSON data type and operators to Postgres, and the API layer implementing document CRUD, queries, and index management. This is the same engine family that powers vCore-based Azure Cosmos DB for MongoDB, and in August 2025 the project moved under the Linux Foundation, which matters for anyone betting a platform roadmap on it: the BSON-in-Postgres layer is now vendor-neutral open source, not a single company's side project.
The payoff FerretDB reports for the rewrite is large: roughly 20x faster query execution than 1.x, materially broader MongoDB compatibility, plus two features 1.x never had — vector search (two vector index types, aimed squarely at AI-driven use cases) and replication support for high availability.
The license stack is the other half of the story. FerretDB itself is Apache 2.0 and DocumentDB is MIT, which is the entire point of the project's existence: MongoDB has shipped under the source-available SSPL since 2018, and teams that want a genuinely open-source document database — one they can embed in a commercial platform without a license review — have been looking for an exit ever since. MongoDB Inc. is, predictably, unimpressed; its May 2025 response essay argues imitators don't serve developers. Read both claims with the vendor discount applied and test the software yourself — which is the theme of the second half of this post.
One framing note before the recipe: FerretDB v2 is a stateless proxy, not a database. Your data lives in Postgres rows as BSON; FerretDB translates the Mongo wire protocol on port 27017 into operations against the DocumentDB extension. That single fact determines the whole operational shape — backups, failover, scaling the data layer, and every gap below all follow from "the database is Postgres."
The concrete CNPG recipe
FerretDB's own guide deploys this on Kubernetes via CloudNativePG, and the shape is refreshingly small. There are two objects: a CNPG Cluster running a DocumentDB-enabled Postgres image, and a FerretDB Deployment plus Service pointing at it.
The Postgres side is where the prerequisite lives. A standard CNPG cluster won't do — the image must ship the DocumentDB extension, and CNPG doesn't execute entrypoint scripts from the image, so the extension has to be preloaded and created explicitly:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgres-cluster
spec:
instances: 3
imageName: 'ghcr.io/ferretdb/postgres-documentdb:17-0.102.0-ferretdb-2.1.0'
enableSuperuserAccess: true
storage:
size: 1Gi
postgresql:
shared_preload_libraries:
- pg_cron
- pg_documentdb_core
- pg_documentdb
parameters:
cron.database_name: 'postgres'
bootstrap:
initdb:
postInitSQL:
- 'CREATE EXTENSION IF NOT EXISTS documentdb CASCADE;'Four things to notice, because each is a gotcha in disguise:
imageNameis a version matrix you now own. It pins a Postgres major (17) and a DocumentDB build (0.102.0) to a FerretDB release (2.1.0) — upgrading any corner of the triangle means checking the other two.- The preload libraries exist because DocumentDB leans on
pg_cron. The three libraries pluscron.database_namewire up the background work the extension needs. - The extension must live in the
postgresdatabase.pg_cronbinds to it, and creating the extension elsewhere fails. - Superuser access is a demo convenience. The guide enables it to connect as the default
postgresuser; beyond a demo, scope that down and manage credentials through Secrets. FerretDB 2.1+ can read the Postgres URL from a file, which plays cleanly with Docker Secrets and external secret stores.
The FerretDB side is then almost boring, which is the compliment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ferretdb
spec:
replicas: 1
selector:
matchLabels:
app: ferretdb
template:
metadata:
labels:
app: ferretdb
spec:
containers:
- name: ferretdb
image: ghcr.io/ferretdb/ferretdb:2.1.0
ports:
- containerPort: 27017
env:
- name: FERRETDB_POSTGRESQL_URL
value: 'postgresql://postgres:<password>@postgres-cluster-rw:5432/postgres'One environment variable carries the entire backend relationship: user, password, the cluster's read-write service endpoint, and the database. Expose port 27017 through a Service, point mongosh at it with a MongoDB connection string, run CRUD, and you are speaking Mongo to Postgres. Any Mongo driver — pymongo, Mongoose, the Go and Java drivers — connects the same way, with no code changes, because the compatibility is at the wire protocol, not a client shim.
What "one more CNPG workload" buys ops — and what it costs
If your fleet already standardized its stateful layer on CloudNativePG, the appeal is structural: a Mongo-compatible tenant database becomes one more CNPG-backed workload instead of a second stateful stack. The backup schedules, point-in-time recovery, failover behavior, connection pooling, monitoring, and Postgres operational knowledge your team already has all transfer directly, because the data plane is Postgres. There is no MongoDB replica set to learn, no MMS/Ops Manager analog to stand up, no second set of runbooks for "the data layer is sick at 3 AM." For a small platform team, consolidating every tenant database onto one operator and one storage engine is worth more than any single feature — it is the difference between operating one stateful system well and two badly.
The costs are real but bounded, and all four trace back to the prerequisite. The custom image is the first: you now track postgres-documentdb builds instead of stock Postgres, and every CVE patch or minor upgrade routes through FerretDB's release of that image. The second is the version triangle — FerretDB, DocumentDB extension, Postgres major — which must move together, so pin all three and test upgrades as a unit.
The third is the postgres-database and superuser shape, mildly off the beaten path for teams that mint per-tenant databases and least-privilege roles. FerretDB's recommended layout wants the extension's home database to be postgres, so plan your tenant-database topology around that rather than fighting it. The fourth is pg_cron itself: a background-job scheduler now runs inside your database to serve the extension — one more thing to monitor, and one more reason to keep cron.database_name pointed where DocumentDB expects.
None of these is a reason to walk away. They are the actual price of the ticket, and they are payable in exactly the currency a CNPG-standardized team already holds: Postgres operational skill.
Honest gaps before promising tenants the endpoint
Here is the checklist to work through before any tenant hears the words "just point your Mongo driver here."
Compatibility is broad, not total — test your workload's operations first. FerretDB is admirably direct about this: the project states it does not aim for 100% feature parity with MongoDB and advises verifying compatibility before migrating. The docs maintain a compatibility page tracking supported commands, and the edges — exotic aggregation stages, edge-case index semantics, admin commands — are where migrations stall. The correct pre-flight is mechanical: capture the actual command surface your tenants' apps use and run it against a staging FerretDB (or FerretDB Cloud, the managed AWS offering, as a reference target) before promising anything.
Change streams and oplog tailing deserve their own test. Anything that tails MongoDB's oplog or leans hard on change streams for event-driven behavior sits on top of semantics FerretDB must emulate over Postgres WAL rather than inherit — community efforts in this space are explicitly tailing-only workarounds. If your tenants are CRUD-and-query apps, this likely never bites. If they run realtime pipelines off change streams, prove that path first; it is the single most likely source of a "worked on Atlas, breaks here" ticket.
Benchmark the vector-search claims yourself. Vector search is new in v2 and marketed toward AI workloads, which is exactly the tenant profile most likely to push it past the demo. Two index types exist and the feature works, but "works" and "meets your recall/latency bar at your data scale" are different statements. Run your embeddings, your queries, your scale — on your hardware — before vector search appears in anything tenant-facing.
Plan the migration path with dsync. FerretDB's documented route for moving existing MongoDB data is dsync, an open-source tool with first-class MongoDB-to-FerretDB support: point it at a source MongoDB URI and a destination FerretDB URI and it moves the data with progress logging. That covers the bulk copy; your runbook still needs the cutover story (dual-write window vs. maintenance freeze), index rebuild verification, and a rollback plan that accounts for data written to FerretDB after the cutover starts.
Track the ecosystem's direction of travel, not just today's snapshot. DocumentDB joining the Linux Foundation and FerretDB's steady 2.x cadence (ARM64 support in 2.2.0, ongoing compatibility work) point the same way: the BSON-on-Postgres stack is accumulating investment rather than stagnating.
That doesn't close any gap on the list above. But it changes the expected value of adopting now and verifying, versus waiting for a parity number the project has told you not to expect.
Who this fits
This stack fits one team profile extremely well: you already run CloudNativePG in production, you have tenants or apps asking for a MongoDB-compatible API, and you refuse to operate MongoDB itself — for licensing, staffing, or stack-consolidation reasons. For that team, FerretDB v2 plus the DocumentDB extension is the rare "have both" deal that survives contact with the details, provided the details above are treated as a checklist rather than fine print.
It fits less well if your tenants need the long tail of MongoDB semantics (heavy change-stream consumers, exotic aggregation) or if your Postgres fleet isn't on Kubernetes/CNPG at all — at that point you're adopting two new things instead of one, and the math changes. Either way, the decision procedure is the same: stand up the two YAML objects, run your real workload's command surface against them, and let the compatibility results — not the marketing — write the tenant promise.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. If your platform story starts with infrastructure you control, star the repo on GitHub and run your next experiment on your own fleet.



