How to Use SlateDB: The Beginner's Guide (First Db::open, Put/Get/Delete, and the Single-Writer Rule)

CodexFuse Team · 2026-11-07T12:10:12.075Z · 20 min read min read

How to Use SlateDB: The Beginner's Guide (First Db::open, Put/Get/Delete, and the Single-Writer Rule)

What is SlateDB and how do you use it?

Learning how to use slatedb starts with one idea: SlateDB is an embedded key-value store that writes all of its data to object storage instead of local disk. It runs inside your own process, like RocksDB, and it is not a database server you connect to over a network. You use it by opening a database against an object store, writing key-value pairs with put, reading them back with get, and deleting them with delete.

The slatedb get started path starts with the Git beginner guide, because the first step is cloning the repository and reading the official examples. This slatedb tutorial follows the official SlateDB documentation, the project README, and the PyPI page for the Python bindings. As of November 2026, the latest release is 0.18.0, which landed four days before this guide was written.

  1. Install Rust and add the slatedb crate to your project.
  2. Open your first database with Db::open against an in-memory store.
  3. Write your first key with put and read it back with get.
  4. Delete the key and confirm it is gone.
  5. Learn the durability rule: await the write or flush before you trust it.
  6. Swap the in-memory store for S3, MinIO, or another object store.
  7. Respect the single-writer rule: one writer, as many readers as you need.

CodexFuse offers no SlateDB tool, so this guide links to the official project for the code and to live CodexFuse guides for the surrounding skills. Everything below comes from sources fetched on 2026-11-07, and every number carries its source with it. No Facebook promotion applies to this guide.

What does SlateDB store, and where does the data actually live?

SlateDB is an embedded storage engine built as a log-structured merge-tree, or LSM-tree. Unlike traditional LSM-tree engines, it writes data to object storage such as S3, GCS, Azure Blob Storage, MinIO, and Tigris, instead of local disk. The payoff is bottomless storage capacity, the durability of your object store, and easy replication, because a crashed server can restart elsewhere and recover from the same buckets.

The trade-off is that object storage has higher latency and higher per-request API costs than local disk. SlateDB answers that with batching on writes, caching on reads, and a design that tolerates 50 to 100 milliseconds of write latency. The official docs list the natural fits: stream processing, serverless functions, durable execution, workflow orchestration, durable caches, and data lakes.

Project snapshotValue
Repositoryslatedb/slatedb on GitHub
Stars3,624
Forks336
Commits1,526
Created2024-03-26
Age956 days, or 2.62 years
Releases35
Latest release0.18.0, four days old
LicenseApache License 2.0
FoundationCommonhaus Foundation member since 2024-12-18

The project is 956 days old and still moving fast. Its 3,624 stars work out to 10.79 stars per fork, and forks are 9.27 percent of stars.

The 1,526 commits average 1.60 commits a day, or 43.6 commits per release, and the 35 releases across 956 days work out to about 13.36 releases a year. Stars arrive at 3.79 a day, or 103.54 stars per release.

SlateDB is written in Rust and its own docs describe it as an open-source embedded key-value database and LSM engine built on object storage. It is a library you link into your program, not a service you deploy. That single fact shapes every decision below, from the first Db::open to the single-writer rule.

What do you need before your first Db::open?

You need a Rust toolchain with Cargo, and the tokio async runtime, because every SlateDB operation is async. You also need an object store to point the database at, and the in-memory store is the right choice for your first run. The official README example uses it, and it needs no credentials, no bucket, and no network.

Pin slatedb to version 0.18 in your Cargo.toml, because the README example writes the version as a star and a star floats to the latest release. A beginner should know exactly which version the examples match, and 0.18 is the version this guide was written against.

What you needWhy it matters
Rust toolchain with CargoSlateDB is a Rust crate you build into your program
tokioThe async runtime every SlateDB example uses
slatedb 0.18The current release this guide matches
An object storeInMemory for the first run, S3 or MinIO after that
Python 3.10 or newerOnly if you want the Python bindings instead of Rust

The GitHub beginner guide covers cloning the repository, which is how you fetch the examples and the source to read alongside this guide. The repository is slatedb/slatedb, and its README is the canonical first example this guide follows.

A slatedb rust example starts with two dependencies in Cargo.toml: slatedb itself and tokio, the async runtime the examples use. The homepage install command is cargo add slatedb tokio with the tokio macros and multi-thread runtime features, and the Cargo.toml form below is the equivalent written out by hand.

[dependencies]
slatedb = "0.18"
tokio = "*"

How do you open your first SlateDB database?

Db::open takes two things: a path string for the database, and an object store. The path is a name inside the store, not a directory on your disk, and the store decides where the bytes actually land. In the first example the store is InMemory, which keeps everything in RAM and throws it away when the process ends.

use slatedb::{Db, Error};
use slatedb::object_store::{ObjectStore, memory::InMemory};
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Error> {
    // Setup
    let object_store = Arc::new(InMemory::new());
    let kv_store = Db::open("/tmp/test_kv_store", object_store).await?;

    // Put
    let key = b"test_key";
    let value = b"test_value";
    kv_store.put(key, value).await?;

    // Get
    assert_eq!(
        kv_store.get(key).await?,
        Some("test_value".into())
    );

    // Delete
    kv_store.delete(key).await?;
    assert!(kv_store.get(key).await?.is_none());

    kv_store.put(b"test_key1", b"test_value1").await?;
    kv_store.put(b"test_key2", b"test_value2").await?;
    kv_store.put(b"test_key3", b"test_value3").await?;
    kv_store.put(b"test_key4", b"test_value4").await?;

    // Scan over unbound range
    let mut iter = kv_store.scan(..).await?;
    // Iterate the rows, then run a bound scan from "test_key1" to "test_key2",
    // then seek to "test_key4"

    // Close
    kv_store.close().await?;

    Ok(())
}

That listing is the README example with one small change: the object store binding lets Rust infer its type instead of spelling out the Arc type annotation. Everything else is the official first example, including the InMemory store, the test keys, and the close at the end.

The homepage shows a newer builder form, Db::builder with a store and build, which does the same open in one expression. Neither form is deprecated, so learn Db::open first and treat the builder as a shorter spelling of the same step.

The InMemory store is for demos and tests only. Real use swaps it for an S3, GCS, Azure, MinIO, or Tigris store through the object_store crate, and that swap is the only change the rest of the code needs. SlateDB re-exports the object_store crate, so any store that implements its ObjectStore trait works.

How do put, get, and delete work?

Put writes a key and a value, both as bytes, get takes a key and returns the value wrapped in Some when the key exists, or None when it does not, and delete removes a key so a later get returns None. All three are async, so each one ends with await.

The example above writes test_key with the value test_value, reads it back, deletes it, and proves the delete by asserting the next get is None. It then writes four numbered keys, test_key1 through test_key4, to set up the scan. That is the whole basic API: get, put, and delete cover the core, and everything else in the crate builds on those three calls.

Keys sort in lexicographic byte order, which matters the moment you scan. The string test_key10 sorts before test_key2, because the comparison reads byte by byte and the character 1 comes before 2. Use fixed-width keys, such as zero-padded numbers, when numeric order matters to your scans.

How do you make a write durable?

A put returns a WriteHandle after updating the in-memory write-ahead log and MemTable, and that return is fast but not the same as durable. To wait for one write to become durable, call await_durable on the handle, and to flush all pending writes at once, call flush on the database.

let handle = kv_store.put(b"user:1", b"Alice").await?;
handle.await_durable().await;
kv_store.flush().await;
Durability choiceWhat it waits forWhen to use it
Ignore the WriteHandleNothing; the write sits in memoryBest-effort writes you can afford to lose
await_durable on one handleThat single write reaching object storageA write that must survive a crash
flush on the databaseAll pending writes reaching object storageCheckpoints, shutdown, and batch boundaries

Writes are batched on purpose. Rather than writing every put to object storage, SlateDB flushes MemTables periodically as string-sorted tables, which keeps the number of PUT requests down. The flush interval is configurable, and the benchmark setup in the comparison section used 100 milliseconds.

Reads get the same treatment in reverse. SlateDB uses in-memory block caches, compression, bloom filters, and local SST disk caches to cut read latency and GET costs. The pattern is consistent: the hot path stays in memory and on local disk, while object storage is the durable home the data always returns to.

What is the single-writer rule?

SlateDB is designed for a single writer. One process owns writes to a database, and opening the same database path with a second writer is an error by design. That rule is not a limitation the project plans to remove; it is the shape the whole engine is built around.

Multiple readers on different nodes can all read the same SlateDB database at the same time. Readers see a consistent view through snapshot isolation, and the read-only reader type is the way to open a database when you only need to look. In Python that is the DbReaderBuilder, and it opens a read-only reader instead of a writer.

Writer fencing is what enforces the rule. Zombie writer processes are detected and prevented from writing to the database, so a stale process that thinks it still owns the database cannot corrupt the live writer's data. Partitioning can be built on top of SlateDB precisely because fencing is supported: split the key space across databases, give each one writer, and let the readers fan out.

How do you swap the demo store for real object storage?

A slatedb object storage deployment points Db::open at S3, GCS, Azure Blob, MinIO, or Tigris instead of the in-memory store. The code does not change shape: the same path string and the same put, get, and delete calls now talk to a bucket instead of RAM. The object_store crate supplies the provider-specific store, and SlateDB supports any object storage that implements its ObjectStore trait.

Object storeWhat it isGood for
Amazon S3The managed object store SlateDB was designed aroundProduction workloads on AWS
Google Cloud StorageGoogle's managed object storeProduction workloads on GCP
Azure Blob StorageMicrosoft's managed object storeProduction workloads on Azure
MinIOS3-compatible object storage you run yourselfLocal development and self-hosting
TigrisGlobally distributed S3-compatible storageMulti-region workloads without managing buckets

MinIO is the cheapest way to try real object storage on your own machine. The Docker beginner guide covers running MinIO in a container, and the what is VPS hosting guide explains the always-on machine a self-hosted MinIO instance lives on. Start with MinIO locally, and move to a managed store when the data matters.

One honesty note: the exact Rust-side setup for an S3 store, including the provider's environment variables, was not verified against the SlateDB docs for this guide. The language bindings resolve a store from a URL such as memory:///, and the object_store crate handles the provider details for the Rust path. Point Db::open at the store your deployment already configures, and check the object_store documentation for the provider you choose.

What are checkpoints, snapshots, and clones?

A checkpoint pins a version of the database so the garbage collector cannot delete the SST files that version needs. Writers use checkpoints to pin a version for reads, and readers use them the same way. Many reader processes can coexist alongside one writer, each holding the version it needs.

A clone forks a database from a checkpoint. The clone shares the source database's SST files instead of copying them, then changes independently from that point on. That makes clones cheap to create and useful for testing, branching a dataset, or giving a reader a stable snapshot to work from.

Version 0.18.0 added a two-phase checkpoint API, and the same release made Db::snapshot and Db::begin synchronous. The previous release, 0.17.0, added checkpoint lifetime configuration, while an earlier release, 0.16.0, raised the garbage-collection interval default to 10 minutes. The direction is clear: checkpoints are becoming a first-class workflow, not an afterthought.

Change data capture turns writes into a durable change stream through the SlateDbWalReader, and the write-ahead log is enabled by default. That means the same log that protects your writes can also feed a downstream consumer, which is one more reason the durability lesson in the earlier section matters.

How do you use SlateDB from Python?

A slatedb python program starts with pip install slatedb, which needs Python 3.10 or newer, and the current release is 0.18.0. The bindings are official, built with UniFFI, and mostly async, so you drive them with asyncio. The package on PyPI is 128.2 megabytes across all wheels and the source distribution, and the install itself is one command.

import asyncio
from slatedb.uniffi import (
    DbBuilder, IsolationLevel, KeyRange, ObjectStore, WriteBatch,
)

async def main():
    store = ObjectStore.resolve("memory:///")
    builder = DbBuilder("demo-db", store)
    db = await builder.build()
    try:
        await db.put(b"user:1", b"Alice")
        value = await db.get(b"user:1")
        assert value == b"Alice"
        batch = WriteBatch()
        batch.put(b"user:2", b"Bob")
        batch.put(b"user:3", b"Carol")
        await db.write(batch)
        scan = await db.scan_prefix(b"user:", KeyRange(start=None, start_inclusive=False, end=None, end_inclusive=False))
        while (row := await scan.next()) is not None:
            print(row.key, row.value)
        tx = await db.begin(IsolationLevel.SERIALIZABLE_SNAPSHOT)
        await tx.put(b"user:4", b"Dora")
        await tx.commit()
    finally:
        await db.shutdown()

asyncio.run(main())

DbBuilder opens a writable database and DbReaderBuilder opens a read-only reader, which mirrors the single-writer rule from the Rust side. A WriteBatch is mutated synchronously and then consumed by one write call, and transactions run at serializable snapshot isolation. The shutdown call at the end explicitly closes the native resources, so do not skip it.

The shorter homepage form is the same idea in fewer lines: resolve the store, build the database, put hello with world, and get it back. There is no separate Python documentation beyond the binding source and slatedb.io, so the PyPI quick start above and the official docs are the references to keep open. The bindings also cover Go, Java, and TypeScript officially, with community bindings for other languages.

Is SlateDB faster than RocksDB?

Readers searching for slatedb vs rocksdb usually want a speed verdict, and the honest answer is that it depends on what you measure. RocksDB is a local-disk engine tuned for years, while SlateDB trades raw local speed for object-storage durability and economics. Any benchmark that runs both on local disk is measuring SlateDB outside its design target.

The independent nixiesearch benchmark from 2026-06-01 ran both engines on the same machine: a 16-core Ryzen 7 7700X with 64 GiB of RAM and a 2 TB NVMe drive, 100 million keys, 16-byte keys, 256-byte values, an 80 percent read and 20 percent write mix, and 4 GiB of block cache on each side. SlateDB ran on a local object-store backend with a 100 millisecond flush interval and durability off. The headline, in the author's own words, is that RocksDB is more than 2 times faster in raw read and write throughput.

The same benchmark gives SlateDB its due. Memory usage is roughly similar between the two engines, but SlateDB shows much lower write amplification, even after adjusting for the smaller number of operations completed. The author's conclusion is that SlateDB is not a drop-in RocksDB on S3 performance replacement, at least not yet, and definitely not in a fully local hot-data benchmark, but the numbers are still encouraging.

SurrealDB published a second comparison with its own SurrealKV 1.0 announcement on 2026-10-13, running all three engines on local disk with synchronous durability, 500,000 keys, 48 worker threads, and 128 clients. Each figure is a single run, SlateDB ran on local disk and not on object storage, and the numbers measure speed under one durability promise, so read the table with that context attached.

Engine, synchronous durabilityPoint readsCreatesUpdatesDeletesScans
SurrealKV6,804,864229,376221,341264,089905,132
RocksDB855,8518,56836,26332,043852,661
SlateDB92,3038,2578,1228,24217,985

The ratios behind that table are stark: SurrealKV is 73.7 times faster than SlateDB on point reads, 27.8 times on creates, 27.3 times on updates, 32.0 times on deletes, and 50.3 times on scans. RocksDB is 9.27 times faster on point reads, 4.46 times on updates, 1.04 times on creates, 3.89 times on deletes, and 47.41 times on scans. Without synchronous durability the picture barely moves: SurrealKV is 72.5 times faster on point reads, and SlateDB with synchronous durability keeps 95.8 percent of its own unsynchronized read speed.

Those numbers are real, and they are also the wrong test for SlateDB. The Redis beginner guide covers the in-memory store readers usually have in mind when they ask about speed, and the contrast is instructive: an in-memory store wins every local benchmark, and still cannot give you the durability and economics of object storage. SlateDB's design trade is that S3 is the source of truth, so a crashed server restarts elsewhere and recovers, with no local state, no control plane, and no replication protocol to operate.

What are the seven mistakes beginners make?

MistakeWhat happensDo this instead
Treating SlateDB as a server databaseYou look for a connection string and a port that do not existLink it into your program; it runs in-process
Opening a second writerThe second writer is fenced off by designGive each database one writer and fan readers out
Trusting a put before it is durableA crash can lose a write that only reached memoryAwait the WriteHandle or call flush first
Using the in-memory store for real dataEverything disappears when the process endsUse S3, MinIO, or another object store for real data
Assuming numeric key ordertest_key10 sorts before test_key2 in byte orderUse fixed-width keys when order matters
Reading benchmark numbers without their contextLocal-disk tests make SlateDB look slowRemember the tests ran outside its design target
Skipping the close or shutdown callNative resources stay open after you are doneClose the database in Rust, shut it down in Python

Every row in that table is a mistake the documentation already warns against, and each one is cheap to avoid once you have seen it. The pattern behind all seven is the same: SlateDB is a library with object-storage semantics, not a server with local-disk habits, and the fastest way to learn it is to respect that difference from the first Db::open.

Is SlateDB ready for production?

SlateDB is pre-1.0 software at version 0.18.0, the project gives no API-compatibility guarantee, and storage-format compatibility is guaranteed only between adjacent versions. Evaluate it on learning and non-critical workloads first, and watch the release notes before trusting it with data you cannot rebuild.

The evidence behind that caution is public. The release schedule promises a new version about every two months at the end of each even month, and the 0.18.0 changelog itself lists a fix for database corruption through a panic.

The previous release, 0.17.0, landed on 2026-09-29, and 0.18.0 followed 35 days later on 2026-11-03. The run from 0.11.0 on 2026-03-03 to 0.18.0 covers 245 days across seven minor versions, or 35.0 days per minor version on average.

The other side of the picture is momentum and adoption. SlateDB joined the Commonhaus Foundation on 2024-12-18, and the README lists 25 adopters, including Dropbox and Prisma, as projects using it. A fast-moving pre-1.0 project with real users is exactly the kind of software a beginner should learn now and deploy carefully later.

Sources

The facts in this guide come from sources fetched on 2026-11-07: the slatedb/slatedb repository on GitHub, the project releases page, the slatedb.io homepage and documentation, the docs.rs page for slatedb 0.18.0, the PyPI page for slatedb 0.18.0, the lib.rs crate page, the nixiesearch benchmark of SlateDB against RocksDB, the SurrealKV 1.0 announcement, and the Commonhaus Foundation announcement. The repository figures are 3,624 stars, 336 forks, 29 watchers, 1,526 commits, and 35 releases, with the repository created on 2024-03-26. The lib.rs download figures come from a crawl dated 2026-10-27 and predate 0.18.0, and the 0.18.0 date of 2026-11-03 is the PyPI upload date.

The code in this guide is quoted from the official documentation and was not executed in a live testbed during this run. The Rust example follows the project README, the Python example follows the PyPI quick start, and the computed figures below were produced by running the arithmetic in Python this run.

from datetime import date
ref = date(2026, 11, 7)
created = date(2024, 3, 26)
print("repo age days:", (ref - created).days)
print("repo age years:", round((ref - created).days / 365, 2))
print("stars per fork:", round(3624 / 336, 2))
print("forks share pct:", round(336 / 3624 * 100, 2))
print("commits per day:", format(1526 / 956, ".2f"))
print("stars per day:", round(3624 / 956, 2))
print("stars per release:", round(3624 / 35, 2))
print("commits per release:", round(1526 / 35, 1))
print("releases per year:", round(35 / 956 * 365, 2))
print("days since 0.18.0:", (ref - date(2026, 11, 3)).days)
print("days since 0.17.0:", (ref - date(2026, 9, 29)).days)
print("days 0.17.0 to 0.18.0:", (date(2026, 11, 3) - date(2026, 9, 29)).days)
print("days 0.11.0 to 0.18.0:", (date(2026, 11, 3) - date(2026, 3, 3)).days)
print("avg days per minor version:", format(245 / 7, ".1f"))
print("SurrealKV read ratio:", round(6804864 / 92303, 1))
print("SurrealKV create ratio:", round(229376 / 8257, 1))
print("SurrealKV update ratio:", round(221341 / 8122, 1))
print("SurrealKV delete ratio:", round(264089 / 8242, 1))
print("SurrealKV scan ratio:", round(905132 / 17985, 1))
print("RocksDB read ratio:", round(855851 / 92303, 2))
print("RocksDB update ratio:", round(36263 / 8122, 2))
print("RocksDB create ratio:", round(8568 / 8257, 2))
print("RocksDB delete ratio:", round(32043 / 8242, 2))
print("RocksDB scan ratio:", round(852661 / 17985, 2))
print("SurrealKV nosync read ratio:", round(6992767 / 96397, 1))
print("SlateDB sync pct of nosync reads:", round(92303 / 96397 * 100, 1))

Frequently Asked Questions

Is SlateDB a database server?

No. SlateDB is an embedded storage engine that runs inside your own process, like RocksDB. There is no server to install, no port to connect to, and no separate process to operate.

Your program opens a database with Db::open, writes with put, reads with get, and closes it when done. The durability comes from object storage, not from a server.

Can two processes write to the same SlateDB database?

No. SlateDB is designed for a single writer, and a second writer opening the same database is fenced off by design. Writer fencing detects zombie writers and prevents them from writing.

Multiple readers on different nodes can read the same database at the same time, and each one sees a consistent view through snapshot isolation. Use the read-only reader when you only need to look.

Does SlateDB work with S3 and MinIO?

Yes. SlateDB writes to any object storage that implements the object_store crate's ObjectStore trait, and the README names S3, GCS, Azure Blob Storage, MinIO, and Tigris. MinIO is the S3-compatible store you can run yourself, which makes it the natural choice for local development.

Start with the in-memory store for your first run, move to MinIO when you want real persistence locally, and move to a managed store when the data matters. The code stays the same; only the store changes.

Is there a Python version of SlateDB?

Yes. The official Python bindings are on PyPI as slatedb, install with pip install slatedb, and need Python 3.10 or newer. The current release is 0.18.0, the same version as the Rust crate.

The bindings are built with UniFFI and mostly async, so you drive them with asyncio. DbBuilder opens a writable database, DbReaderBuilder opens a read-only reader, and shutdown closes the native resources.

How is SlateDB different from RocksDB?

RocksDB is a local-disk LSM engine tuned for years, while SlateDB is a cloud-native LSM engine that writes to object storage. RocksDB wins raw local throughput, and SlateDB wins durability, economics, and the ability to restart anywhere.

The nixiesearch benchmark puts RocksDB at more than 2 times faster in a local hot-data test, while SlateDB shows much lower write amplification. Choose RocksDB for local speed and SlateDB when object storage is the point.

Featured on Twelve Tools Hunt for Tools Featured on LaunchBuff Launch Llama Tools Launch your MCP Top Web Development Companies in the US - OnToplist.com Designer Listings Listed on SeeWhatNewAI Featured on SubmitMySaas Featured on AI Agents Directory Product Wing SaaS Wheel