foundationdb-rs

Async, runtime-agnostic Rust bindings for FoundationDB's transactional, ordered key-value store.

Library
Cargo
v0.11.0
230stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
80/100Excellent
Development Activity96
Maintenance72
Community76
Maturity56
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
86/100Excellent
Architecture85
Code Quality92
Innovation78
Learning Curve88

foundationdb-rs is the community-maintained Rust client for FoundationDB, the distributed, transactionally consistent key-value database originally built at Apple and later open-sourced. It wraps FoundationDB’s C API in safe, async Rust, exposing a Database/Transaction model where every read and write happens inside retryable, ACID transaction closures - the same idiom used by FoundationDB’s official Python, Java, and Go bindings.

Beyond raw key-value access, the crate ships a directory layer for hierarchical namespacing, a tuple layer for typed key encoding, ready-made recipes (leader election, ranked registers), a pluggable retry runner with observability hooks, and an opt-in client-side budget for bounding per-attempt resource usage. The project verifies its own correctness against FoundationDB’s official BindingTester on an hourly cron and maintains a from-scratch deterministic simulation harness, a level of rigor uncommon in community database bindings.

What You Get

  • A Database/Transaction API wrapping FoundationDB’s C client in safe, async Rust
  • A directory and tuple layer for typed, hierarchical key namespacing
  • Ready-made recipes for leader election and ranked registers
  • A pluggable retry runner (TransactionRunner) with hooks and custom retry policies
  • An opt-in client-side budget for bounding per-attempt byte/call usage

Common Use Cases

  • Building a transactional metadata store - services that need strongly consistent, ordered key-value storage without running their own consensus layer use FoundationDB via this crate as the storage backend.
  • Implementing distributed coordination primitives - teams use the leader-election and ranked-register recipes to build leader election or distributed locks directly on FDB transactions.
  • Layering a custom data model over FDB - applications use the tuple and directory layers to build typed, namespaced schemas (e.g. document or graph stores) on top of raw ordered keys.
  • Bounding per-request resource usage - services with strict latency/cost budgets use the client-side budget API to cap how many bytes/calls a single transaction attempt can consume before it’s aborted.

Under The Hood

Architecture lib.rs re-exports a set of focused modules: api.rs handles network initialization and API-version selection; database.rs defines Database, a safe wrapper around a raw FDBDatabase C pointer whose run() method executes retryable closures through runner.rs; transaction.rs (nearly 2000 lines) implements Transaction, marshaling get/set/clear/atomic_op/watch calls to the C API via future.rs, which wraps raw FDBFuture pointers into polled Rust futures. runner.rs decomposes retry logic into three independent pieces - the attempt, purely observational RunnerHooks, and a RetryPolicy that alone can change the outcome - while budget.rs tracks per-attempt byte/call usage entirely decoupled from the runner and from the C client’s own timeout/size-limit options. The tuple module (delegated to the foundationdb-tuple crate) provides typed key encoding, and directory/ (directory_layer.rs, directory_subspace.rs, node.rs) implements a layered namespace abstraction over raw ordered keys. The workspace cleanly separates generated FFI (foundationdb-sys, produced at build time by foundationdb-gen from fdb.options/fdb_c.h) from the safe high-level crate, procedural macros (foundationdb-macros), and a dedicated simulation harness - so a change to the core Transaction/Database layer ripples through retries, directory, and recipes alike.

Tech Stack Rust 2024 edition with an MSRV of 1.85.1, built on the futures 0.3 traits rather than a specific async runtime, so it composes with tokio, async-std, or any other executor (examples use tokio). foundationdb-sys supplies generated FFI bindings to FoundationDB’s C client, built via a build.rs that can either link against a system install or embed the C headers with the embedded-fdb-include feature. Additional dependencies include async-trait, async-recursion, static_assertions, libc, rand, and optional uuid/num-bigint/tracing integrations; dev-dependencies include tokio (full), sha2, byteorder, bytesize, and data-encoding for test fixtures. A Nix flake provides a reproducible dev environment, and cargo aliases (build-fdb-latest, test-fdb-latest) wrap FDB version feature flags for local development without a full cluster install.

Code Quality The foundationdb/tests/ directory exercises real transaction semantics (api.rs, atomic.rs, budget.rs, conflict_ranges.rs, database.rs, directory.rs, error.rs, future.rs) against a live cluster, backed by an unusually deep CI setup - eleven separate GitHub Actions workflows covering standard CI, code coverage, MSRV checks, a Nix build, rustdoc generation, dependency auditing, and, notably, cron-correctness and pr-correctness workflows that run FoundationDB’s official BindingTester against thousands of seeds on a recurring schedule. Error handling is explicit via FdbError/FdbResult plus a dedicated FdbBindingError and RetryableError/RetryDecision trait for retry-aware propagation. #[deny(missing_docs)] is applied per-module (budget, env, fdb_keys, runner) to force public-API documentation, clippy is wired into the cargo aliases, and static_assertions enforces select invariants at compile time.

API Design The public API favors the FDB closure idiom - db.run(|trx, _| async move { … }) - keeping ergonomics close to the official Python/Java/Go bindings while staying async and runtime-agnostic. Retry behavior, previously a single opaque loop in most bindings, is exposed as a composable Attempt/Hooks/Policy triad so callers can attach custom backoff logic or metrics without touching the core loop. Two features stand out as unusual for a community database client: a deterministic, opt-in client-side budget that tracks per-attempt resource usage independently of the C client’s own limits, and direct integration with FoundationDB’s official correctness-testing tooling plus a from-scratch deterministic simulation harness (foundationdb-simulation, foundationdb-simulation-tracing) - the same bar official bindings are held to.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search