11 releases (4 breaking)
new 0.5.2 | Mar 21, 2025 |
---|---|
0.5.1 | Mar 19, 2025 |
0.4.0 | Dec 31, 2024 |
0.3.0 | Nov 17, 2024 |
0.1.4 | Aug 30, 2024 |
#92 in Database interfaces
2,307 downloads per month
1MB
25K
SLoC

Introduction
SlateDB is an embedded storage engine built as a log-structured merge-tree. Unlike traditional LSM-tree storage engines, SlateDB writes data to object storage (S3, GCS, ABS, MinIO, Tigris, and so on). Leveraging object storage allows SlateDB to provide bottomless storage capacity, high durability, and easy replication. The trade-off is that object storage has a higher latency and higher API cost than local disk.
To mitigate high write API costs (PUTs), SlateDB batches writes. Rather than writing every put()
call to object storage, MemTables are flushed periodically to object storage as a string-sorted table (SST). The flush interval is configurable.
put()
returns a Future
that resolves when the data is durably persisted. Clients that prefer lower latency at the cost of durability can instead use put_with_options
with await_durable
set to false
.
To mitigate read latency and read API costs (GETs), SlateDB will use standard LSM-tree caching techniques: in-memory block caches, compression, bloom filters, and local SST disk caches.
Checkout slatedb.io to learn more.
Get Started
Add the following to your Cargo.toml
:
[dependencies]
slatedb = "*"
tokio = "*"
Then you can use SlateDB in your Rust code:
use slatedb::Db;
use slatedb::config::DbOptions;
use slatedb::SlateDBError;
use slatedb::object_store::{ObjectStore, memory::InMemory};
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), SlateDBError> {
// Setup
let object_store: Arc<dyn ObjectStore> = Arc::new(InMemory::new());
let options = DbOptions::default();
let kv_store = Db::open_with_opts(
"/tmp/test_kv_store",
options,
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::<Vec<u8>, _>(..).await?;
let mut count = 1;
while let Ok(Some(item)) = iter.next().await {
assert_eq!(
item.key,
format!("test_key{count}").into_bytes()
);
assert_eq!(
item.value,
format!("test_value{count}").into_bytes()
);
count += 1;
}
// Scan over bound range
let mut iter = kv_store.scan("test_key1"..="test_key2").await?;
assert_eq!(
iter.next().await?,
Some((b"test_key1", b"test_value1").into())
);
assert_eq!(
iter.next().await?,
Some((b"test_key2", b"test_value2").into())
);
// Seek ahead to next key
let mut iter = kv_store.scan::<Vec<u8>, _>(..).await?;
let next_key = b"test_key4";
iter.seek(next_key).await?;
assert_eq!(
iter.next().await?,
Some((b"test_key4", b"test_value4").into())
);
assert_eq!(iter.next().await?, None);
// Close
kv_store.close().await?;
Ok(())
}
SlateDB uses the object_store
crate to interact with object storage, and therefore supports any object storage that implements the ObjectStore
trait. You can use the crate in your project to interact with any object storage that implements the ObjectStore
trait. SlateDB also re-exports the object_store
crate for your convenience.
Documentation
Visit slatedb.io to learn more.
Features
SlateDB is currently in the early stages of development. It is not yet ready for production use.
- Basic API (get, put, delete)
- SSTs on object storage
- Range queries (#8)
- Block cache (#15)
- Disk cache (#9)
- Compression (#10)
- Bloom filters (#11)
- Manifest persistence (#14)
- Compaction (#7)
- Transactions
- Merge operator (#328)
- Clones (#49)
License
SlateDB is licensed under the Apache License, Version 2.0.
Foundation
SlateDB is a member of the Commonhaus Foundation.

Dependencies
~19–51MB
~822K SLoC