induwara.lk
Opinionrustdatabasesopen-source

TurboKV: what a Rust key-value store's benchmarks really say

TurboKV is a fast embedded key-value store in Rust, but the most useful thing in the repo is how carefully it labels its own benchmark numbers. Here is how to read them.

Induwara Ashinsana5 min read
TurboKV project logo banner displayed at the top of the GitHub repository README
Image: GitHub

TurboKV, a new embedded Rust key-value store, showed up on Hacker News this week with the kind of headline that usually makes me close the tab: "insanely fast." I opened the repository expecting a benchmark chart with no axis labels. I found the opposite.

The speed claims are real enough. But the genuinely instructive part of this project is the paragraph underneath the numbers, and that is what I want to talk about.


🔍 What TurboKV actually is

Strip the adjectives and it is a small, specific thing:

  • Embedded, not networked. It runs inside your process as a library. There is no server, no port, no connection pool.
  • Async, built on Tokio. insert, get and remove are all awaited.
  • LSM-tree shaped: memtables, SSTables, a write-ahead log, background compaction.
  • Apache 2.0, requires Rust 1.85+, currently at version 0.6.0.

The API is about as small as this class of database gets:

let db = Db::open_with_options("./my-database", DbOptions::durable()).await?;
db.insert(b"user:1", b"Ada").await?;
assert_eq!(db.get(b"user:1").await?, Some(b"Ada".to_vec()));
db.close().await?;

Three durability presets ship in the box, and the README is blunt about what each one actually promises:

Preset When your write is acknowledged Honest reading
fast() In-memory visibility, no WAL A cache. Crash means data loss.
durable() (default) Appended to the WAL, no per-write sync Survives a process crash, not a power cut
paranoid() WAL group finished sync_all Strongest, still bounded by your disk's honesty

📊 Read the benchmark table, not the headline

Here is the published comparison against fjall 2.11.2 and redb 2.6.3, measured on an Apple M4 with 32 GiB of RAM on 2026-08-28. Throughput is acknowledged keys per second, higher is better.

Workload TurboKV Recoverable fjall Buffer redb Eventual TurboKV / fjall
Sequential fill (1 key/txn) 1,407,678 485,252 1,397 2.901×
Random fill (1 key/txn) 834,137 456,924 1,549 1.826×
Overwrite (1 key/txn) 853,083 446,733 1,516 1.910×
Batch (100 keys/txn) 2,272,259 511,600 80,197 4.441×
Batch (1,000 keys/txn) 2,333,582 572,671 134,636 4.075×

Now look at what the author does with that redb column. Instead of banking the thousand-fold win, the README states that redb's Durability::Eventual performs a macOS F_BARRIERFSYNC on every transaction, while TurboKV and fjall stop at their process-crash-recoverable OS-cache boundaries. It then calls its own single-key rows "architectural context rather than a like-for-like durability claim."

Key takeaway: a benchmark that tells you which of its own rows are unfair is worth more than a benchmark that is 4× faster. The second one you have to re-run yourself; the first one you can reason about.

The project also renames its own default. The preset is called durable() in code, but in the benchmark table it appears as "Recoverable", because it survives a crashed process and not a lost power supply. I have reviewed vendor benchmarks that would never make that distinction in public.


💰 Why "embedded" is the interesting word for a small team

Most of us here are not sizing a fleet. We are running one box, and the monthly bill is in dollars against an LKR income. That changes which database property matters.

A networked store like Redis or Postgres costs you a second process, its own memory floor, a socket, a supervisor entry and a backup story. An embedded store costs you a directory.

Concern Networked store Embedded store like TurboKV
Extra process to run Yes No
Baseline RAM Its own allocation Yours, inside your app
Network round trip per read Yes No
Shared across services Yes No, single owner
Ops surface Config, auth, ports A folder on disk

That last row is the trade, and it is a real one. TurboKV states plainly that one open Db handle exclusively owns its data directory. If two of your services need the same data, this is the wrong tool and no benchmark number changes that.

Watch the memory defaults if you are on a 1 GB or 2 GB VPS. Every preset starts with a 64 MiB memtable and a 64 MiB block cache, so roughly 128 MiB is spoken for before your application allocates anything. Both are public fields you can lower before opening. If your keys are actually embeddings rather than short strings, the arithmetic gets steeper fast, and our AI vector storage calculator will size that for you before you provision the box.


🛠️ Four things I would check before shipping it

  1. It is 0.6.0. That is a pre-1.0 version number on a storage engine. Storage bugs are the expensive kind, because they are discovered later than they happen.
  2. The build flags are not optional. The persisted Bloom-filter format uses hardware AES. You are told to build with RUSTFLAGS="-C target-feature=+aes,+sse2" on x86_64 and +aes,+neon on ARM. Miss this in your CI image and you find out at runtime.
  3. Dropping the handle is not a clean shutdown. Call close() or close_with_status(). This has to survive your panic paths and your container's stop signal, not just the happy path.
  4. The benchmark hardware is not your hardware. Those numbers come from an Apple M4 with 32 GiB of RAM on APFS. Your $6 VPS has shared vCPUs and network-backed storage. Expect a different shape, not just a smaller multiple.

Bottom line: treat the published throughput as evidence that the design is sound, not as a number you will reproduce.


💡 What this means for you

If you are building a Rust service that needs local ordered storage, a queue, a cache with range scans, or an index that must survive a restart, TurboKV is worth an afternoon. The API surface is small enough to learn in one sitting and the scan and batch semantics are documented in unusual detail.

If you are not writing Rust, take the other thing instead. The habit worth stealing from this repo is the discipline of publishing what your numbers do not prove: the hardware, the durability boundary, the row that is not a fair fight, and the raw artifact so someone can check you. That applies to your own benchmarks, your client-facing performance claims, and your final year project.

Fast is a claim anyone can make. Legible is the harder one, and it is the one that survives review.

#rust#databases#open-source
IA

Induwara Ashinsana

Information Systems student at UCSC and Executive Director at Ryzera Technologies. Writes about software, AI, and what it means for builders in Sri Lanka.

About the author →

Keep reading