The short answer
Pick FerretDB if you want simple document storage under an open-source licence, and your app needs neither transactions nor change streams, and is the only one using the database. Pick MongoDB for anything that relies on transactions, change streams, schema validation or a login per app that only reaches its own database: in our tests FerretDB accepted all of these without doing them, and MongoDB was also faster at most of the work.
What we tested
We installed both on the same fresh Melonslab VC-P Alloy (2 vCPU, 8 GB) with Debian 13, one after the other, by following our guides FerretDB database server and MongoDB database server step by step. Each ran under a user of its own, with TLS, passwords and the settings each guide gives for 8 GB of memory.
Both guides publish port 27017. To run both on one server, we changed only the two PublishPort lines in FerretDB's ferretdb.pod to 127.0.0.1:27018:27017 and 10.8.0.1:27018:27017, and opened 27018 on wg0 in ufw as well. Inside its pod FerretDB still listens on 27017, so the guide's mongosh alias and backup script work unchanged. If you only run one of them, keep the guides as they are.
Then we ran the same Python code, with PyMongo 4.10, against both:
- a compatibility script that tries logins, transactions, change streams, views, collation, validation and more, and compares the results;
- a benchmark with 105,000 orders and 5,000 customers: inserts, indexed finds, an aggregation pipeline, a join, and a mix of updates and reads, run three times on each;
- the small notes app from both guides, over the WireGuard address.
We also measured memory after a reboot, disk, and the backups and restores from each guide, and moved a dump from each database to the other.
The numbers
| FerretDB 2.7.0 | MongoDB 9.0.2 | |
|---|---|---|
| Containers | 2: FerretDB, PostgreSQL 17.6 with DocumentDB 0.107.0 | 1: MongoDB |
| Memory, idle after a reboot | about 95 MB (FerretDB 7, PostgreSQL 19, plus 66 MB of PostgreSQL's shared cache) | about 210 MB |
| Memory after the queries | about 155 MB | about 200 MB |
| Cache limit set by the guide | 2 GB (shared_buffers) | 3 GB (wiredTigerCacheSizeGB) |
| Images on disk | 1.78 GB, plus 1.09 GB for the mongo image with the tools | 1.09 GB |
| Data on disk after the benchmark | about 1 GB, of which 880 MB PostgreSQL's write-ahead log | 285 MB, of which 200 MB MongoDB's journal |
| The same data, freshly restored | 133 MB | 224 MB |
Collections and indexes (dbStats) | 50 MB and 21 MB | 18 MB and 7 MB, compressed |
| First start, image download included | about 1 minute 45 seconds | about 55 seconds |
| Steps in our guide | 11 | 11 |
| Nightly backup | 9 seconds: a dump, 3.9 MB, and a copy of PostgreSQL, 12.8 MB | 2.5 seconds: a dump, 3.9 MB |
| Restore one database from the dump | 11 seconds | 8 seconds |
| Restore everything into an empty volume | 17 seconds | 25 seconds |
Memory is measured from each app's own control groups. podman stats shows PostgreSQL at about 20 MB, because it does not count the shared memory PostgreSQL uses as its cache. Both caches grow as your data is used, up to the limits above. The whole server, with both running and the test data loaded, used 780 MB after a reboot.
The disk numbers depend on what you have done lately. PostgreSQL keeps up to 1 GB of write-ahead log by default, and reuses it, so after many writes FerretDB's volume reached about 1 GB. MongoDB's journal takes about 200 MB from the start. Restored fresh, with no history, FerretDB took less.
Compatibility
We ran one script against both. The rows are what it tried, and the cells what happened.
| What we tried | FerretDB 2.7.0 | MongoDB 9.0.2 |
|---|---|---|
| The app's login reads another app's database | allowed | refused, not authorized |
| The app's login writes to another app's database | allowed | refused, not authorized |
Create a read-only login with createUser | failed, logins are made in PostgreSQL | refused for the app's login; works for admin |
| A write inside a transaction, seen from outside before the commit | visible | not visible |
The same write after abortTransaction | still there | gone |
Change stream (watch()) | failed: $changeStream is not supported yet | got the insert |
| A view of 3 of 5 documents | created, returned 0 | returned 3 |
Case-insensitive search with collation({locale: "sv", strength: 2}) | found 0 of 2 | found 2 of 2 |
A $jsonSchema validator, then a document that breaks it | stored anyway | refused, Document failed validation |
Capped collection with max: 3, 10 inserts | 10 documents | 3 documents |
| Time series collection | became an ordinary collection | a time series collection |
| Hidden index | failed: not supported yet | worked |
collMod to add a validator or change a TTL | failed | worked |
Profiler (profile) | failed: no such command | worked |
mapReduce | failed: no such command | worked |
$where | failed | refused, as MongoDB 9.0 does by default |
Text search, $lookup, 2dsphere $near, TTL and unique indexes | worked | worked |
The FerretDB guide's step 9 lists more of what worked on both, among them most aggregation stages. Whatever FerretDB did not support, it either refused with an error, which your app notices, or accepted and ignored, which it does not. The second kind is the dangerous one: transactions, views, collation, validators and capped collections all looked fine until we checked the result.
Setup
Both guides are built the same way: a user of their own, a certificate authority of your own, TLS for every connection, secrets in podman secret, access only from the server and over WireGuard, and a backup with a timer. Both worked as written.
MongoDB is one container. It needs a replica set of one member, started by hand once, so that transactions and change streams work, and apps must add directConnection=true to their connection string. It also wants two kernel settings for transparent huge pages, which its guide adds.
FerretDB is a pod of two containers, FerretDB and PostgreSQL with the DocumentDB extension, and needs a little more care: a PostgreSQL role for FerretDB made at the first start, PostgreSQL's memory settings, and logins made with psql, because createUser in mongosh does not work. FerretDB also sends usage statistics until you switch them off, which its guide does. Its images are bigger, and you need the mongo image as well for mongosh and the backup tools.
Day-to-day use
For an app, both look the same. The notes app from the guides ran unchanged against both; only the connection string differed. mongosh, mongodump and mongorestore work with both, and mongosh warns on FerretDB that This server or service appears to be an emulation of MongoDB.
The difference is in what happens when something goes wrong. On MongoDB, an app's login can only touch its own database, a transaction that fails leaves nothing behind, and a validator stops bad documents. On FerretDB, every login can read and write every database, and the other two quietly do nothing. If you run more than one app, each app needs its own FerretDB, with its own user, pod and port.
MongoDB also has the tools around it: change streams for live updates, the profiler for slow queries, and explain() output in the format MongoDB's documentation describes. FerretDB's explain() shows PostgreSQL's plan instead.
Performance
The same benchmark, three times on each, one database at a time while the other was idle. The numbers are the median of the three runs. Every operation went over TLS through Podman's port forwarding, as in the guides, which adds about a millisecond to each.
| Workload | FerretDB 2.7.0 | MongoDB 9.0.2 |
|---|---|---|
| Insert 100,000 orders in batches of 1,000 | 5.4 s (18,500 a second) | 4.6 s (21,800 a second) |
| Insert 5,000 orders one at a time | 18 s (270 a second) | 22 s (230 a second) |
| Create two indexes | 2.0 s | 1.2 s |
| 10,000 indexed finds, 10 orders each | 41 s (250 a second) | 15 s (680 a second) |
Aggregation ($match, $unwind, $group, $sort), 10 times | 3.6 s | 2.0 s |
$lookup join of 2,000 orders, 10 times | 0.9 s | 0.9 s |
| 20,000 operations, half updates, half reads, 1 client | 77 s (260 a second) | 54 s (370 a second) |
| The same with 8 clients at once | 29 s (695 a second) | 29 s (690 a second) |
update_many on a quarter of the orders | 5.8 s | 1.3 s |
Single writes waited for the disk on both, and varied between runs: the mix with one client ran at 147 to 396 operations a second on MongoDB, and 223 to 283 on FerretDB. Reads were steadier. A single find by _id took 1.3 ms on MongoDB and 2.3 ms on FerretDB, and a ping 0.9 ms and 1.8 ms: FerretDB translates every command into SQL first. We checked that FerretDB used the index for the finds; it did, it was just slower per query.
Both gave the same answers. On this data set the differences are milliseconds per request; with many reads per page, or large updates, they add up.
Resources
FerretDB used less memory at rest, about 95 MB against 210 MB, and FerretDB itself only 7 to 10 MB: the work is done by PostgreSQL. MongoDB's WiredTiger cache starts larger. Both stay well within 8 GB, and either runs next to other apps.
MongoDB stored the same documents in a third of the space, because WiredTiger compresses collections and indexes. FerretDB's collections and indexes took 71 MB, MongoDB's 25 MB. On disk, the logs matter more than the data at this size, as the table shows.
FerretDB needs nearly three times the disk for images, 2.87 GB with the tools against 1.09 GB.
Updates and backups
MongoDB's guide follows the 9.0 tag, and podman auto-update installs every 9.0 release by itself. A new major version is an update by hand, one version at a time, and you switch on its features afterwards with setFeatureCompatibilityVersion, so you can go back until then.
FerretDB's guide pins both images, because each update is done by hand: new tags for FerretDB and PostgreSQL, a restart, and ALTER EXTENSION documentdb UPDATE in PostgreSQL. When we checked FerretDB's GitHub page on 14 October 2026, its newest release was still 2.7.0, from November 2025, and the last change to its code was from February 2026. The DocumentDB extension had moved on, to 0.117 and release candidates for 1.0, but FerretDB's image ships 0.107. Keep an eye on the project before you depend on it.
MongoDB's backup is one mongodump with the oplog, a copy of one moment, in 2.5 seconds here. FerretDB's guide backs up two ways, a mongodump and a copy of PostgreSQL's data, in 9 seconds. Every restore we tried came back with all 105,000 orders and their indexes, and the app's login worked afterwards.
Moving between them works one way better than the other. FerretDB's dump restored into MongoDB with all its indexes. MongoDB's dump restored into FerretDB with all its documents, but mongorestore stopped at the indexes with createIndex.collation is not implemented yet, so only _id was indexed. Moving from MongoDB to FerretDB means making the indexes again by hand, which we did not test.
Licence and cost
We checked the projects' own pages and source code on 14 October 2026.
- FerretDB is open source under the Apache 2.0 licence, and made by FerretDB Inc. It runs on PostgreSQL, under the PostgreSQL licence, and the DocumentDB extension, under the MIT licence, which Microsoft started and which is now developed at its own
documentdbproject on GitHub. You may run it, change it and offer it as a service to others. FerretDB's documentation names no paid edition, only community help on Slack and GitHub and a contact form. - MongoDB Community Server is under the Server Side Public License (SSPL) version 1, which MongoDB, Inc. wrote in 2018. The Open Source Initiative has not approved it as open source. You may run it for your own apps, commercial ones included, and change it. If you offer MongoDB itself as a service to others, you must publish the source code of everything you use to run that service. The drivers,
mongoshand the database tools are under Apache 2.0. MongoDB sells Enterprise Advanced, with among other things LDAP and Kerberos logins and auditing, and its hosted service, Atlas; we did not price them.
Both are free to run on your own server. MongoDB is a trademark of MongoDB, Inc., and FerretDB is not MongoDB.
Which one to pick
FerretDB suits one app that stores and looks up documents, where an open-source licence matters to you or your customers, or where you already know PostgreSQL. Its weak points are serious: transactions, views, collation and validators are accepted and ignored, there are no permissions per login, it was slower at most of our tests, and the project had not released anything for eleven months when we checked. Run your app's own tests against it before you move. Follow the FerretDB guide; it runs comfortably on a VC-P Alloy.
MongoDB suits anything that relies on transactions, change streams, schema validation or a login per app, and most apps written for MongoDB, which may use those features without saying so. Its weak points are the SSPL, which is not open source and restricts offering it as a service, a larger memory and journal footprint from the start, and a replica set to set up even with one server. Follow the MongoDB guide, on a VC-P Alloy.
Together they used under 800 MB with the test data, so a VC-P Alloy can also run both, as on our test server.