One engine, multi-workloads, full durability.
You can explore the full results, methodology, and per-database breakdowns at .
Why we ran these
Database benchmarks are notoriously easy to game, and difficult to get right. Different hardware, different durability settings, different client libraries, a workload that happens to suit one engine's indexing strategy - any of those will tilt the numbers. So we did three things:
- Ran every database on the same hardware - an AMD Ryzen Threadripper 9970X (32C/64T), 128 GiB DDR5, NVMe storage, Ubuntu 24.04.
- Used the same open-source harness - crud-bench - with each workload translated into each engine's native query language so no database is penalised for an unfamiliar dialect.
- Configured every engine for production-grade durability - fsync on, snapshot isolation, no in-memory shortcuts (except where explicitly noted for embedded comparisons).
We also went out of our way to give every database a fair shot. Rather than running each engine on its out-of-the-box defaults, we used optimised configurations across the board - the same kind of tuning a production team would apply before going live. That meant raising connection and worker pool limits to match the 128-client load, sizing buffer pools, page caches, and shared memory to take advantage of the available 128 GiB of RAM, enabling parallel query execution and prepared-statement caching where supported, setting WAL and checkpoint intervals to values recommended by each project's own performance guides, and turning on the indexes and storage engines (InnoDB, WiredTiger, RocksDB-backed stores, etc.) that each database's documentation recommends for OLTP workloads. The goal was to make sure no engine was held back by a conservative default - if a database underperforms here, it isn't because we left it on its laptop-friendly starter config.
Workloads run with 128 clients issuing 48 concurrent queries each, against datasets of a single table with 5 - 15 million rows of mixed-type records (strings, integers, floats, UUIDs, datetimes, booleans, large text fields, geospatial data, and nested objects and arrays).
About last time
We owe a word on durability. The previous round of benchmark results ran with fsync disabled for every engine - leaving each database's writes in the OS page cache rather than flushed to disk. Every database in the comparison ran with the same setting, so nothing was being "fudged" relative to the other engines, but we didn't make the setting explicit, and the headline numbers ended up describing a workload that most production deployments would not likely run.
This round is different. Every database in these benchmarks runs with full disk durability enabled - fsync on, WAL flushed on every commit, no buffered writes hiding behind the page cache. The configuration files for each engine are checked into the so anyone can audit them. The numbers above are what each engine sustains when every committed transaction is on disk before the client gets an acknowledgement. That's slower than the cache-friendly numbers you'll find in some marketing posts, ours included, but it's the only honest way to compare databases that are going to outlive a power outage.
How far SurrealDB has come
The biggest story is internal. Across three major releases, we've fundamentally rebuilt the query, parser, and storage layers:
| Workload | SurrealDB 1.x | SurrealDB 2.x | SurrealDB 3.x |
|---|---|---|---|
| Mixed CRUD (50% write) | 78k ops/s | 107k ops/s | 141k ops/s |
| Full-table scans | 0.06 ops/s | 0.09 ops/s | 11 ops/s (164×) |
| Indexed lookups | 32 ops/s | 44 ops/s | 104 ops/s (3.2×) |
Between SurrealDB 2.x and 3.x alone:
- 31% faster mean CRUD throughput
- 58% faster batch operations
- 11,894% faster non-indexed full-table scans
- 136% faster indexed queries
- Tail latency improvements of 27% (CRUD), 32% (batches), 59% (indexed), and 99% (scans)
The scan number is not a typo. The SurrealDB 3.x query planner and storage engine eliminates the per-row decoding overhead that dominated earlier versions, which is why a workload that used to take minutes now completes in seconds.
How we compare to other databases
SurrealDB is a durable, transactional, multi-model database, so the comparisons that matter most are against the primary databases people actually evaluate it against - Postgres for relational, MongoDB for document, Neo4j for graph. Here's how the same workload looks across those three categories, run on the same hardware with each engine on a tuned production-grade configuration.
vs. PostgreSQL (and MySQL)
CRUD throughput (ops/s) and bulk-read metrics:
| Workload | SurrealDB | Postgres | MySQL |
|---|---|---|---|
| Create | 122k | 83k | 22k |
| Read | 254k | 327k | 195k |
| Update | 106k | 81k | 22k |
| Delete | 156k | 86k | 22k |
| Write throughput (C+U+D mean) | 128k | 84k | 22k |
| count(*) on 5M rows | 12 | 8 | 42 |
SurrealDB is faster than Postgres on every write operation - roughly 1.5× faster creates, 1.3× faster updates, and 1.8× faster deletes - while Postgres still edges ahead on raw single-record reads. Against MySQL the gap widens dramatically: SurrealDB is 5 - 7× faster on writes.
Averaged across creates, updates, and deletes, SurrealDB delivers ~1.5× the write throughput of Postgres - the headline number the benchmarks page leads the Relational category with - and beats Postgres by ~1.5× on full-table counts. Postgres' query planner is 30 years old and still ahead on indexed predicate filtering; we're not pretending otherwise, and we're working on closing that gap in 3.1.
vs. MongoDB (and ArangoDB)
CRUD throughput (ops/s) and bulk-read metrics:
| Workload | SurrealDB | MongoDB | ArangoDB |
|---|---|---|---|
| Create | 122k | 183k | 1.0k |
| Read | 254k | 200k | 255k |
| Update | 106k | 160k | 0.9k |
| Delete | 156k | 200k | 1.0k |
| Filter scan (unindexed, ops/s) | 8.3 | 3.0 | 8.5 |
This is the closest race. MongoDB still leads on single-record writes, while SurrealDB is ~1.3× faster on reads - and the picture flips on heavier workloads. On predicate filter scans against unindexed tables - the headline figure the benchmarks page uses for the Document category - SurrealDB is roughly 2.7× faster than MongoDB, with consistently lower mean and p99 latency. Against ArangoDB's document engine, SurrealDB is between 100× and 150× faster on writes.
vs. Neo4j (and ArangoDB)
CRUD throughput (ops/s) and bulk-read metrics:
| Workload | SurrealDB | Neo4j | ArangoDB |
|---|---|---|---|
| Create | 122k | 42k | 1.0k |
| Read | 254k | 174k | 255k |
| Update | 106k | 50k | 0.9k |
| Delete | 156k | 44k | 1.0k |
| Filter scan (indexed, mean ops/s) | 421 | 12 | - |
SurrealDB outperforms Neo4j across every CRUD operation - roughly 2 - 3.5× faster on writes and 1.5× faster on reads - while running the same graph traversals through the same engine that handles documents and tables.
The gap on filtered scans is even more dramatic. Across indexed predicate filter queries - the headline metric the benchmarks page uses for the Graph category - SurrealDB is roughly 35× faster than Neo4j. No separate database, no separate query language, no separate operational story.
Reference point: Redis and KeyDB
For raw key-value throughput, we also ran SurrealDB's in-memory engine (with append-only persistence) against Redis and KeyDB:
| Operation | SurrealDB | Redis | KeyDB |
|---|---|---|---|
| Create | 300.8k | 85.8k | 79.5k |
| Read | 288.1k | 367.9k | 348.6k |
| Update | 300.6k | 89.0k | 85.2k |
| Delete | 279.3k | 100.6k | 100.0k |
That's roughly 3× faster than Redis on writes, updates, and deletes, while offering durable, snapshot-isolated transactions and a full query language Redis doesn't have. Redis still wins on large 1,000-record batch operations and edges ahead on single-record reads.
Embedded mode (vs. SQLite)
SurrealDB's embedded engine runs the same SurrealQL on the same disk format as the server.
| Workload | SurrealDB embedded | SQLite |
|---|---|---|
| Create | 110k | 1.3k |
| Read | 138k | 154k |
| Update | 145k | 1.3k |
| Delete | 101k | 1.3k |
| Filter scan (unindexed, ops/s) | 39 | 6 |
| Filter scan (indexed, mean ops/s) | 7.5k | 2.3k |
Against SQLite, SurrealDB is roughly 85× faster on creates, 110× faster on updates, and 75× faster on deletes, with single-record reads in the same ballpark. On predicate filter scans against unindexed tables it's around 6.5× faster than SQLite, and on indexed filter scans, around 3× faster.
The full breakdowns - including p50, p95, and p99 latencies, batch sizes from 100 to 1,000 rows, indexed and non-indexed predicate filters, and full-text search - are on the .
Closing the remaining gaps
The numbers above are an honest snapshot, not a finish line. There are still workloads where Redis, MongoDB, and Postgres beat us - large batch operations vs. Redis, single-record writes vs. Mongo, indexed predicate filtering vs. Postgres - and we know exactly where each gap comes from. Closing those gaps is the central focus of the SurrealDB 3.1 cycle.
What we're actively working on:
- Batch path rewrites to bring 100-row and 1,000-row batched ops closer to Redis throughput, including better client-side pipelining and a leaner server-side batch executor.
- A smarter query planner with cost-based optimisation, predicate pushdown into the storage engine, and richer index selectivity statistics - the work that gets us to parity with Postgres on indexed filter scans.
- Storage layer improvements for the document workload - more compact in-place updates, sharper write amplification, and tighter integration between the key encoding and the document path resolver - which is where Mongo currently has the edge on single-record writes.
- Vector and graph traversal optimisations as those workloads land in the benchmark suite, so the multi-model story holds up at the same rigour as CRUD.
The goal isn't "fastest at one thing." It's to be fastest, or competitive, across every workload that matters, while keeping the one property no specialist engine can match: a single query language - SurrealQL - that handles relational, document, graph, key-value, time-series, vector, and full-text search data in the same database, with the same transactional guarantees, on the same disk format - and the same engine, whether you're running it embedded inside an application, on a single server, at the edge close to your users, or distributed across hundreds of nodes for horizontal scale. We don't think you should have to choose between Postgres, Mongo, Neo4j, and Redis - or between a database that runs on a developer laptop and one that runs across a global fleet. We think a single database should run all four shapes of workload at production speed, anywhere it needs to live, and the SurrealDB 3.x numbers above are the strongest evidence yet that it can.
Why this matters for AI agents
There's a reason we keep pushing on this combination of data models, and it's not historical accident. Agent memory is multi-model by nature. A useful AI agent needs structured facts about the world (relational), semi-structured context and tool outputs (document), entity and event relationships (graph), embeddings for semantic recall (vector), keyword and BM25 retrieval over its corpus (full-text search), episodic and temporal context (time-series), and fast session and cache state (key-value) - and it needs all of that in a single transactionally consistent store, because the moment those shapes live in separate databases, you've built a glue-code problem that breaks every time the schema changes or the model is updated.
Agents also need that memory close to where they run. An agent reasoning inside a browser, a phone, an in-vehicle system, or a per-tenant edge worker can't afford a round trip to a central database for every retrieval. The fact that SurrealDB runs as an embedded engine on the same disk format as the distributed server - with the same query language and the same transactional guarantees - is what makes it usable as the memory layer for agents that move fluidly between local, edge, and centralised deployments. Faster CRUD, faster scans, and faster indexed lookups aren't just abstract benchmark wins; they're how many tools an agent can call, how much context it can recall per turn, and how many concurrent agents a single host can support. That's the workload SurrealDB 3.x is built for, and it's the workload the next round of benchmarks - covering vector search, graph traversal, and full-text retrieval - will measure head-on.
What's next
We intend to expand the benchmarks to also cover CockroachDB, TiDB, MongoDB, and Aerospike for distributed comparisons, which we'll publish in a future round. We also plan to expand the workload set to include graph traversals vector search, and full-text search, two areas where the single-engine, multi-model design of SurrealDB shows its biggest advantages.
Until then: the harness is open source, the results are reproducible, and we'd love for you to run them on your own hardware and tell us what you find.