MongoDB vs FerretDB vs DocumentDB: benchmarks across two runs
In our MongoDB vs FerretDB benchmark, the biggest lesson was how much our own storage and PostgreSQL defaults mattered. That post compared MongoDB with stock and tuned FerretDB. This follow-up brings all three engines into one comparison: the earlier MongoDB and tuned FerretDB results, alongside a new FerretDB versus standalone DocumentDB run.
These tables span two benchmark runs, not a single three-engine test. MongoDB was measured in August and was not rerun in October. FerretDB appears twice so you can see the result from each run. Every performance column is dated, and the original article remains the source for the August measurements and their full configuration caveats.
In the October run, DocumentDB delivered 20-33% more throughput on pure reads, 24-35% more on the 95% read / 5% update mix, and 7-12% more on the 50/50 mix. FerretDB had lower p99 update latency in every 50/50 row. At 256 client threads, that was 931 ms for FerretDB versus 2,226 ms for DocumentDB.
Those are two useful results, and a throughput-only chart would hide the second one. This is one complete run per stack, not a repeated trial with confidence intervals.
What we compared in October
Here, DocumentDB means the open-source PostgreSQL-based project and its documentdb-local:pg17-1.0.0 package. It does not mean Amazon DocumentDB, and neither Amazon DocumentDB nor MongoDB Atlas was tested.
FerretDB also uses PostgreSQL with a DocumentDB extension. The FerretDB project describes that stack; the DocumentDB project provides its own MongoDB protocol gateway. We compared the two packaged paths a client can connect to, not PostgreSQL against a wholly unrelated storage engine.
| Component | FerretDB arm | Standalone DocumentDB arm |
|---|---|---|
| Frontend package | ghcr.io/ferretdb/ferretdb:2, digest pinned | ghcr.io/documentdb/documentdb/documentdb-local:pg17-1.0.0, digest pinned |
| PostgreSQL package | FerretDB's postgres-documentdb:17, digest pinned | Bundled in the DocumentDB Local image |
| Recorded PostgreSQL version | 17.6 | 17.11 |
| Storage profile | 16K ZFS records, 2 GiB ARC cap | Same |
| PostgreSQL memory | 2 GiB shared buffers | Same |
| Commit settings | synchronous_commit=on, full_page_writes=on | Same |
The different PostgreSQL minor versions and bundled extension builds matter. These results compare whole stacks. They do not isolate gateway overhead or prove that replacing one frontend alone produces the measured difference. Full image digests and captured settings are in the measurement record.
The setup
We used two separate OVH d2-8 instances in US-EAST-VA-1 on October 23, 2026. Each had 4 vCPUs, 8 GB RAM, Debian 13, and a 100 GB network-attached high-speed volume. Each ran one database stack and its own YCSB client. Client CPU and memory therefore shared the machine with the database on both arms.
This follows the hardware profile and workload structure of the earlier article. It measures this small dedicated-instance profile, not shared-plan performance or every possible deployment of either engine.
- YCSB commit
66302f301b13f60d4bcb2f29f478586bb1d6f2e0, Java 17.0.20. - 10 million records loaded per engine, then 1 million operations per phase.
- Workloads C (100% read), B (95% read / 5% update), and A (50% read / 50% update).
- 16, 64, and 256 client threads; 32 threads for the initial load.
- Write concern
w=1; a 600-second cap per workload phase. - PostgreSQL
max_wal_size=8GB,effective_io_concurrency=200,random_page_cost=1.1, andmax_connections=300on both arms.
The dataset is roughly 10 GB of logical field data, larger than machine RAM. Physical storage size, compression, and the pages actually accessed are different quantities; this does not prove that every request had to go to disk.
The suite ran C, then B, then A, with thread counts ascending within each workload. It loaded once per engine and reused the data across phases. It did not reset caches or randomize phase order. The same client pool behavior as the earlier article applies: the default MongoDB driver pool is 100, so 256 client threads does not mean 256 simultaneous database connections.
All three engines, with each run labeled
The August columns reproduce the published MongoDB 8.0.29 and tuned-default FerretDB 2.7 results from our earlier benchmark. They exclude its stock FerretDB and relaxed-durability variants. MongoDB ran on August 18 and the tuned FerretDB arm on August 19, on separate boxes of the same profile. The October columns come from the new October 23 run described above.
All columns use the 4 vCPU, 8 GB hardware profile and the same workload shapes. Matching those does not eliminate differences in machines, dates, software packages, caches, or storage performance. Compare the August pair and the October pair within their documented conditions; do not read an October-to-August ratio as a measured engine speedup.
Throughput is rounded to whole operations per second. For the October run, all 18 workload phases completed their full million operations before the time cap; the YCSB summary counters reported successful returns for all reads and updates. Both initial loads reported 10 million successful inserts. This is a client return-status check, not an independent audit of every stored value.
Workload C: 100% read
| Client threads | MongoDB (Aug 2026), ops/sec | FerretDB tuned (Aug 2026), ops/sec | FerretDB tuned (Oct 2026), ops/sec | DocumentDB (Oct 2026), ops/sec |
|---|---|---|---|---|
| 16 | 755 | 3,888 | 4,265 | 5,122 |
| 64 | 756 | 4,065 | 4,342 | 5,338 |
| 256 (pool-limited) | 753 | 3,851 | 4,100 | 5,462 |
Workload B: 95% read / 5% update
| Client threads | MongoDB (Aug 2026), ops/sec | FerretDB tuned (Aug 2026), ops/sec | FerretDB tuned (Oct 2026), ops/sec | DocumentDB (Oct 2026), ops/sec |
|---|---|---|---|---|
| 16 | 700 | 3,611 | 3,792 | 4,711 |
| 64 | 750 | 3,919 | 3,841 | 5,196 |
| 256 (pool-limited) | 712 | 3,526 | 3,838 | 5,189 |
Workload A: 50% read / 50% update
| Client threads | MongoDB (Aug 2026), ops/sec | FerretDB tuned (Aug 2026), ops/sec | FerretDB tuned (Oct 2026), ops/sec | DocumentDB (Oct 2026), ops/sec |
|---|---|---|---|---|
| 16 | 491 | 1,631 | 1,886 | 2,016 |
| 64 | 464 | 1,752 | 1,783 | 2,005 |
| 256 (pool-limited) | 465 | 1,586 | 1,708 | 1,821 |
DocumentDB led FerretDB throughput in all nine October matched rows. In the historical August comparison, tuned FerretDB led MongoDB across the same workload shapes. The original article describes the MongoDB arm as I/O-bound on that small-memory setup; that result should not be generalized to a larger-memory deployment. In October, DocumentDB's advantage over FerretDB was largest on the read-heavy mixes and narrowed on the 50/50 mix. Neither October stack gained mixed-workload throughput by moving from 16 to 256 client threads.
Update p99 latency: the part throughput misses
Lower is better. October values are milliseconds, converted from YCSB's microsecond summaries and rounded to one decimal place. August values retain the whole-millisecond precision published in the original latency table. That table reported only the 50/50 mix; a dash means the historical value is not included in that source table, not zero.
| Workload | Client threads | MongoDB (Aug), ms | FerretDB tuned (Aug), ms | FerretDB tuned (Oct), ms | DocumentDB (Oct), ms |
|---|---|---|---|---|---|
| 95/5 | 16 | - | - | 102.0 | 96.2 |
| 95/5 | 64 | - | - | 156.9 | 306.9 |
| 95/5 | 256 | - | - | 263.4 | 315.4 |
| 50/50 | 16 | 156 | 100 | 92.1 | 103.8 |
| 50/50 | 64 | 664 | 388 | 324.1 | 687.1 |
| 50/50 | 256 | 1,682 | 849 | 931.3 | 2,226.2 |
At 64 threads on the 50/50 mix, DocumentDB delivered about 12% more throughput, but its update p99 was 687 ms versus FerretDB's 324 ms. At 256 threads, DocumentDB's throughput lead was about 7%, while update p99 was 2.23 seconds versus 0.93 seconds.
That is why an application with a latency budget should look beyond the operations-per-second column. Higher aggregate throughput did not mean better slow-request behavior in this run. These are observed tails, not a diagnosis of their cause: we did not collect enough profiling evidence to attribute them to checkpoints, gateway scheduling, or another component.
How this relates to the MongoDB comparison
Read the earlier MongoDB vs FerretDB benchmark alongside this one. It contains the MongoDB measurements, the stock-versus-tuned FerretDB comparison, and the storage/memory ablation that led to the profile used here.
The two FerretDB columns are useful context: even the tuned profile produced different numbers between August and October. They are a visible reminder that hardware class and configuration labels do not make separate runs interchangeable. We have shown the historical MongoDB results so readers can compare all three engines, while keeping each result attached to the experiment that produced it. A fresh three-engine run would be needed to establish a current matched ranking.
The useful comparison is:
| Question | Evidence |
|---|---|
| How did MongoDB and FerretDB compare on the earlier small-instance setup? | The earlier article's measured tables and caveats |
| How did the two PostgreSQL-backed document stacks compare on October 23? | This article's matched FerretDB and standalone DocumentDB run |
| Which of all three wins today on my application? | Not answered by these two runs; requires a fresh matched test and application compatibility checks |
What this run does not settle
One run per configuration gives no estimate of run-to-run variance. Separate VMs and volumes can vary despite matching specifications. The PostgreSQL and extension builds are not identical. The client runs on the database machine, and the fixed workload order carries cache and update history into later phases.
YCSB's point reads and updates also do not test aggregation pipelines, application-specific indexes, transactions, change streams, failover, replication, or full MongoDB compatibility. w=1 with synchronous PostgreSQL commits enabled is the tested configuration, not a replicated durability or crash-recovery guarantee. Neither stack was tested with the earlier article's relaxed-durability opt-in.
For a read-heavy workload on this hardware, DocumentDB's throughput result is a reason to evaluate it. For a mixed workload with a strict slow-update budget, FerretDB's lower measured p99 is equally relevant. Neither result is enough on its own to justify migrating a production application.
Download the measurements
The CSV contains the October run only: all nine workload rows and the load phase for each of its two engines, including operation counts and p99 latency. The JSON measurement record contains the parsed YCSB summary counters, image pins, PostgreSQL settings, and SHA-256 hashes of the retained source archives. Raw archives are kept privately because setup and connection logs contain credentials; the downloads expose only metrics and non-secret configuration.
Both suites completed, the logs were saved, and deletion of both temporary instances and both attached volumes was confirmed. The measurements, not the temporary servers, are what we kept.
Try the MongoDB-compatible workflow on Layerbase
We are big fans of both DocumentDB and FerretDB. Both projects give developers valuable ways to work with documents through the MongoDB-compatible protocol on PostgreSQL, and we want both to succeed. Publishing their strengths and tradeoffs helps you choose the right fit for your application.
Layerbase Cloud lets you use that MongoDB-compatible workflow with database branching: create an isolated branch for development, a migration rehearsal, or a CI run. Bring your existing driver and test the commands your application relies on; protocol compatibility does not mean every MongoDB feature behaves identically.
You can get that workflow at a fraction of the price of a dedicated Atlas M30 deployment. For a concrete example, our Dedicated 8GB preset is $65/month, while MongoDB's own billing example prices an AWS M30 at $0.54/hour, about $394 over 730 hours. That puts our preset at roughly one-sixth of that 730-hour estimate. Prices checked October 23, 2026; Atlas pricing varies by region and configuration. This is a single-node Layerbase preset with backups and branching versus an Atlas three-node replica set, so the availability architectures differ. It is not a claim about every Atlas tier, and we did not benchmark Atlas.
If you want to run MongoDB itself locally, you can use the Layerbase CLI or Layerbase Desktop. We do not host MongoDB itself in Layerbase Cloud; our cloud MongoDB-compatible options are FerretDB and DocumentDB.
Create a database on Layerbase Cloud, try your application's queries, and branch it before your next migration. For the background behind these results, start with our original MongoDB vs FerretDB benchmark.
Keep reading
- MongoDB vs FerretDB on the same hardware: the benchmark, and what we had to fix to run it fairlyYCSB against MongoDB 8.0 and FerretDB 2.7 on the exact hardware behind our $65/mo dedicated preset. Once our own tuning was right, FerretDB held 3-4x MongoDB throughput on the mixed workload and about 5x on reads. The corrected numbers, what had to be fixed first, and what we are not claiming.
- Introducing DocumentDB 1.0: Our 19th Cloud EngineDocumentDB 1.0 joins Layerbase Cloud alongside FerretDB. Run MongoDB-compatible workloads on Solo or Pro, or try it locally on Linux without Docker.
- MongoDB Atlas alternatives: flat pricing and a document database you can branchWhat you actually get when you leave MongoDB Atlas for managed FerretDB on Layerbase: the same wire protocol and driver, a flat monthly price instead of a per-tier meter, branching Atlas does not offer, and an honest list of the cases where you should stay put.
- Run FerretDB on Windows (No Docker, No WSL)FerretDB v2 needs a PostgreSQL extension that is not on Windows yet. We built custom binaries to run FerretDB v1 natively on Windows, no Docker or WSL.