Open-source project
surrealdb/surrealkv avatar
surrealdb/surrealkv

SurrealKV: a Rust key-value store on an LSM tree with a 1.0 release

A low-level, versioned, embedded, ACID-compliant, key-value database for Rust

647 stars49 forksRustApache-2.0

At a glance

What is it?
SurrealKV is SurrealDB's embedded, low-level key-value engine, built on a log-structured merge tree with an asynchronous commit pipeline, encrypted at rest by default and published as version 1.0.0. It suits a Rust developer who needs a local, durable, transactional store inside an application, and it is the wrong tool if you want a query language or a networked database.
Who is it for?
SurrealKV fits a Rust service or desktop application that needs a durable, transactional, embedded store with no server to run, especially one that wants encryption at rest without wiring a separate mechanism, and the 1.0.0 release means the API has stopped moving. It is the wrong choice if you need queries, indexes or a multi-user protocol, because this is the low-level engine underneath SurrealDB rather than the database itself.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The storage engine, not the database

SurrealKV is described as a low-level, versioned, embedded, ACID-compliant key-value database for Rust, and the readme is more specific still: an embedded key-value storage engine with an async commit pipeline.

It comes from the SurrealDB organisation, and the relationship matters. The keywords in the package manifest list lmdb, rocksdb, sled, redb and tikv, which are the key-value and LSM engines it is positioned against, and the workspace includes crates called surrealkv-compat-rocksdb, surrealkv-compat-v1 and surrealkv-compat-indxdb. Those compatibility crates are the clearest statement of what this project is: a storage engine with enough surface to stand in for the engines SurrealDB previously used, so that the database above it can change its storage layer without changing its behaviour.

So SurrealKV is not SurrealDB. SurrealDB is the multi-user database with a query language, a web interface and a network protocol. SurrealKV is the part underneath, the thing you would embed in a Rust binary, and it exposes a tree rather than tables and records.

The audience that follows from this is a Rust developer writing an application that needs a local, durable, transactional key-value store. The readme names the intended settings directly: high-throughput server workloads, embedded systems, and desktop applications. On the server side, the storage engine is versioned, which is the property that lets a cluster replicate and fail over rather than lose data.

The licence is Apache-2.0, the crate is on crates.io as surrealkv, the API documentation is on docs.rs, and the project page is surrealdb.com.

An asynchronous commit pipeline with synchronous reads

The architectural description in the readme is short and specific. The engine is built on a modern Log-Structured Merge tree architecture. Commits go through an asynchronous commit pipeline, point reads and iteration are synchronous, and get_async is available as an opt-in asynchronous point read.

That is a meaningful set of choices rather than a default. An LSM tree gives fast point reads because data is served largely from memory, and it gives efficient sequential scans because the data is sorted on disk. What it costs is write amplification, since data is written to a memtable, flushed to a sorted run, and merged in the background. For a workload that is read-heavy and written in batches, that is a good trade. For a workload that rewrites the same key many times, it is not.

The split between an asynchronous commit pipeline and synchronous reads has an important consequence for how a caller reasons about durability. A commit that returns does not necessarily mean the bytes are on the platter, and the readme describes the benchmark configuration with a --sync flag that makes every commit fully durable and flushed to disk before it returns. That flag is the difference between a fast commit and a durable one, and an application has to decide which it needs per workload rather than per database.

The dependency list in the manifest shows the shape of the storage engine underneath. artmap and byteslice are the in-memory and buffer structures, snap handles snapshots, zstd and lz4_flex are the compressors, crc32fast and xxhash-rust with the xxh3 feature are the checksums, aes-gcm is the encryption primitive, and quick_cache and parking_lot handle caching and locking. tokio with the rt, sync and macros features gives the async runtime, and artmap and affinitypool sit alongside it for the work distribution. The result is a genuine storage engine rather than a wrapper.

Encryption at rest is on by default, and the failure mode is deliberate

The feature list in the manifest has one entry, and it is the interesting one. The default feature set is default = ["encryption"], and the comment explains the consequence in unusual detail: without the feature, Options::validate refuses a configured key manager, so Tree::new fails with Error::InvalidArgument and creates nothing, and data is never written unencrypted by accident.

That is a careful design and worth reading twice. The usual failure mode for an encryption feature is that a developer disables it for speed, forgets, and writes plaintext. Here, disabling the feature does not silently fall back to plaintext storage; it makes the constructor fail if a key manager is configured. The code refuses to create a tree rather than create an unencrypted one.

The requirement is that a key manager is configured. The manifest does not describe the key manager interface, so the details of how keys are derived, rotated or stored are not visible in the repository listing, and a team evaluating this needs to look at the API documentation for that. The one thing the manifest does establish is that encryption at rest is transparent, that it is on unless you opt out, and that opting out while configuring a key manager is an error rather than a downgrade.

For an embedded database that will hold session tokens, credentials or personal data on a laptop or an embedded device, having encryption on by default removes an entire class of mistake. The cost is that the engine is doing encryption work on the write path, and that behaviour is included in the numbers the project publishes for the synchronous durability configuration.

The published benchmark numbers, and what they assume

The readme publishes benchmark tables, and they are worth reading with their setup in mind rather than as headline figures.

The hardware is specified: an AMD Ryzen Threadripper 9970X with 32 cores and 64 threads at 5.48 GHz, 128 GB of DDR5 RAM and a 4TB PCIe 4.0 NVMe SSD. The workload is 500,000 keys across 48 concurrent worker threads with 128 clients, and 5,000,000 iterations of each range scan, run through the crud-bench harness.

With synchronous durability, the project reports 6,804,864 point read operations per second, 229,376 creates, 221,341 updates, 264,089 deletes and 905,132 scans. It describes those as 7.95 times faster than RocksDB on point reads and 26.8 times faster on creates. Without synchronous durability, point reads rise to 6,992,767 per second, creates to 321,715, updates to 274,172, deletes to 307,034 and scans to 896,366.

Two observations are worth making. First, the readme is explicit that each figure is a single run, and that Fjall, ReDB, LMDB and Libmdbx were not benchmarked with synchronous durability because at this dataset size the runs were too slow to finish in the available time. That is a more useful disclosure than a table with asterisks hidden at the bottom, and it tells you the durability comparison is not like-for-like across every engine.

Second, the comparison is not uniform in SurrealKV's favour. Without synchronous durability, RocksDB is ahead on creates, updates and deletes, and LMDB is ahead on range scans, while SurrealKV leads decisively on point reads. The scan profile table breaks the scan result down further by scan type, and it shows the same pattern, with SurrealKV leading on limit scans and on keys-plus-limit, but at 402 full-count operations per second it is well behind LMDB's figures on that particular scan shape.

So the honest summary is that this engine's advantage is read throughput, and that its write advantage in the durability configuration comes at a cost that the non-durable numbers make visible.

Running the tests, checking the licences, and building the CLI

The Makefile is short and it is a good summary of what this project considers non-negotiable.

The build target depends on check, so the build cannot skip the checks. The check target runs cargo deny check licenses, then cargo fmt --all -- --check, then cargo clippy --workspace --all-targets with warnings denied. Checking the licences of every dependency during a normal build is unusual and deliberate for a database that is about to be embedded in someone else's product, and clippy with -D warnings means the lint failures are build failures.

The test target runs the workspace tests with backtrace enabled:

bash
test:
	RUST_BACKTRACE=1 cargo test --workspace

There are two CLI targets. build-cli compiles the surrealkv-cli package, and install-cli installs it from crates/surrealkv-cli with cargo install --path, which is the route to a binary on your PATH. There is also a readme target that runs scripts/sync-crate-readme.sh to regenerate CARGO.md, the crates.io readme, from README.md, so the two never drift.

The rest of the tree supports that. There are benches/ and a proptest-regressions/ directory, which is where property-based test failures get recorded so they stay fixed. The manifest pins a minimum Rust version of 1.86 and uses edition 2021. There is a clippy.toml, a deny.toml for the licence checks, a .rustfmt.toml, a SECURITY.md, a release.toml, a Cargo.lock, and a CARGO.md that serves as the crates.io readme.

The examples directory holds one file, wasi_fs_test.rs, which is a hint about a direction of travel: a WASI filesystem test suggests the engine is being exercised against a WebAssembly system interface, matching the readme's mention of running a Tree in a browser and in a dedicated Web Worker with files in the Origin Private File System.

Where SurrealKV is the wrong choice

The first limitation is the one the project itself leads with: it is low-level. There is no query language here, no schema, no network protocol and no multi-user access model. If you want to store documents and query them, SurrealKV is not the thing to reach for, and SurrealDB is.

The second is the LSM trade-off. Log-structured merge trees are excellent at reads and sequential scans and at write-heavy workloads with large batches. They are poor at the pattern where one key is updated repeatedly, because each update produces a new version that has to be merged eventually. The published numbers show a read engine with strong point-read performance, and the write figures in the non-durable configuration trail RocksDB. A workload of small random writes to a small working set is where you would expect this to be weakest.

The third is durability semantics. The asynchronous commit pipeline with an opt-in synchronous mode means the caller has to make an explicit choice, and the readme's benchmark table shows the size of that choice in the create and update figures. An application that assumes a successful commit is a durable commit, without asking for the synchronous mode, will be wrong.

The fourth is the size of the dependency tree. A Cargo.lock, a deny.toml, a licence check on every build and a list of compression, hashing and encryption crates is a lot of supply chain for an embedded store, and a team with a policy about what may be linked into a shipped product has to review it rather than trust it.

The fifth is the maturity of the 1.0 release. Version 1.0.0 shipped on 2026-10-13, after a long 0.x line that included 0.21.4 and 0.21.3 in August 2026. A 1.0 marks a stability promise, and the compatibility crates named after RocksDB, v1 and indxdb suggest a storage-layer swap that is still in progress behind it. The last push was on 2026-10-20, a week after the release, so the tree is already ahead of the tag.

Editorial conclusion

SurrealKV fits a Rust service or desktop application that needs a durable, transactional, embedded store with no server to run, especially one that wants encryption at rest without wiring a separate mechanism, and the 1.0.0 release means the API has stopped moving. It is the wrong choice if you need queries, indexes or a multi-user protocol, because this is the low-level engine underneath SurrealDB rather than the database itself. Before adopting it, read the get_async and commit pipeline behaviour, check the minimum Rust version of 1.86 against your toolchain, and confirm you can live with the LSM write amplification, noting that the last push was on 2026-10-20 and the 1.0.0 release was on 2026-10-13.

Frequently asked questions

What is SurrealKV and how does it relate to SurrealDB?

SurrealKV is the low-level, versioned, embedded, ACID-compliant key-value storage engine that SurrealDB is built on, written in Rust. It is published separately on crates.io as surrealkv, and the workspace includes compatibility crates for RocksDB, the previous v1 engine and indxdb.

Is encryption at rest enabled by default in SurrealKV?

Yes, the default feature set is default = ["encryption"]. Without the feature, Options::validate refuses a configured key manager, so Tree::new fails with Error::InvalidArgument and creates nothing, and data is never written unencrypted by accident.

How do commits behave in SurrealKV?

Commits go through an asynchronous commit pipeline, while point reads and iteration are synchronous. An opt-in asynchronous point read is available as get_async, and the benchmarks are run with a --sync flag that makes every commit fully durable and flushed to disk before it returns.

How do I build and test SurrealKV?

The Makefile build target depends on check, which runs cargo deny check licenses, cargo fmt --all -- --check and cargo clippy with warnings denied, before cargo build --all-targets and cargo doc. The test target runs RUST_BACKTRACE=1 cargo test --workspace, and install-cli installs the command line tool from crates/surrealkv-cli.

What licence is SurrealKV released under and what Rust version does it need?

Apache-2.0, with the licence file in the repository root. The package manifest requires Rust 1.86 or newer and uses edition 2021, and the newest release is 1.0.0 from 2026-10-13 with the last push on 2026-10-20.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. surrealdb/surrealkv on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/surrealdb-surrealkv.svg)](https://hysenlabs.com/projects/surrealdb-surrealkv)

Was this useful?