{"id":51514740,"url":"https://github.com/jamesgober/bison-db","last_synced_at":"2026-07-08T10:01:45.627Z","repository":{"id":363292284,"uuid":"1261066613","full_name":"jamesgober/bison-db","owner":"jamesgober","description":"An embedded, document-oriented database for Rust - schemaless documents, secondary indexes, and ACID single-file storage, with zero network and zero external services.","archived":false,"fork":false,"pushed_at":"2026-06-08T09:05:54.000Z","size":158,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-08T10:12:11.444Z","etag":null,"topics":["bison","database","document-database","document-store","embedded","embedded-database","nosql","reps","rust","schemaless"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamesgober.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["jamesgober"]}},"created_at":"2026-06-06T07:35:41.000Z","updated_at":"2026-06-08T09:02:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jamesgober/bison-db","commit_stats":null,"previous_names":["jamesgober/bison-db"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/jamesgober/bison-db","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesgober%2Fbison-db","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesgober%2Fbison-db/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesgober%2Fbison-db/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesgober%2Fbison-db/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamesgober","download_url":"https://codeload.github.com/jamesgober/bison-db/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesgober%2Fbison-db/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35260671,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-08T02:00:06.796Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bison","database","document-database","document-store","embedded","embedded-database","nosql","reps","rust","schemaless"],"created_at":"2026-07-08T10:01:43.603Z","updated_at":"2026-07-08T10:01:45.548Z","avatar_url":"https://github.com/jamesgober.png","language":"Rust","funding_links":["https://github.com/sponsors/jamesgober"],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n    \u003cimg width=\"99\" alt=\"Rust logo\" src=\"https://raw.githubusercontent.com/jamesgober/rust-collection/72baabd71f00e14aa9184efcb16fa3deddda3a0a/assets/rust-logo.svg\"\u003e\n    \u003cbr\u003e\n    \u003cb\u003ebison-db\u003c/b\u003e\n    \u003cbr\u003e\n    \u003csub\u003e\u003csup\u003eEMBEDDED DOCUMENT DATABASE\u003c/sup\u003e\u003c/sub\u003e\n\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://crates.io/crates/bison-db\"\u003e\u003cimg alt=\"Crates.io\" src=\"https://img.shields.io/crates/v/bison-db\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://crates.io/crates/bison-db\" alt=\"Download bison-db\"\u003e\u003cimg alt=\"Crates.io Downloads\" src=\"https://img.shields.io/crates/d/bison-db?color=%230099ff\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://docs.rs/bison-db\" title=\"bison-db Documentation\"\u003e\u003cimg alt=\"docs.rs\" src=\"https://img.shields.io/docsrs/bison-db\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/jamesgober/bison-db/actions\"\u003e\u003cimg alt=\"GitHub CI\" src=\"https://github.com/jamesgober/bison-db/actions/workflows/ci.yml/badge.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/rust-lang/rfcs/blob/master/text/2495-min-rust-version.md\" title=\"MSRV\"\u003e\u003cimg alt=\"MSRV\" src=\"https://img.shields.io/badge/MSRV-1.85%2B-blue\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n\u003cbr\u003e\n\n\u003cdiv align=\"left\"\u003e\n    \u003cp\u003e\n        \u003cstrong\u003ebison-db\u003c/strong\u003e is an \u003cb\u003eembedded, document-oriented database\u003c/b\u003e for Rust: store, index, and query \u003cb\u003eschemaless documents\u003c/b\u003e entirely in-process, with no server, no network, and no external services. It is the document-store counterpart to an embedded key-value store, giving you rich nested records and secondary indexes linked directly into your binary.\n    \u003c/p\u003e\n    \u003cp\u003e\n        It is built for \u003cb\u003edurability\u003c/b\u003e and \u003cb\u003espeed\u003c/b\u003e: \u003cb\u003eACID\u003c/b\u003e writes through a write-ahead log, \u003cb\u003esingle-file storage\u003c/b\u003e that is trivial to ship and back up, and \u003cb\u003esecondary indexes\u003c/b\u003e for fast queries over document fields. \u003ccode\u003ebison-db\u003c/code\u003e is the first member of the \u003cb\u003eBison\u003c/b\u003e family of embedded databases.\n    \u003c/p\u003e\n    \u003cbr\u003e\n    \u003chr\u003e\n    \u003cp\u003e\n        \u003cstrong\u003eMSRV is 1.85+\u003c/strong\u003e (Rust 2024 edition). Schemaless documents. Single-file storage. Crash-safe, embedded, zero-network.\n    \u003c/p\u003e\n    \u003cblockquote\u003e\n        \u003cstrong\u003eStatus: stable (\u003ccode\u003e1.0.0\u003c/code\u003e).\u003c/strong\u003e The document model, the single-file store, secondary indexes with field and range queries, a configurable durability policy, and space-reclaiming compaction are all implemented; hardened with fuzz-tested parse/recovery paths, a randomized soak test, and a sustained-load concurrency soak; and \u003ca href=\"./docs/PERFORMANCE.md\"\u003ebenchmarked head-to-head\u003c/a\u003e against a peer engine. The \u003ca href=\"./docs/FORMAT.md\"\u003eon-disk format\u003c/a\u003e (version 1) and the \u003ca href=\"./docs/API.md\"\u003epublic API\u003c/a\u003e are a stability commitment: no breaking change until 2.0, per semantic versioning.\n    \u003c/blockquote\u003e\n\u003c/div\u003e\n\n\u003chr\u003e\n\u003cbr\u003e\n\n\u003ch2\u003eWhat it does\u003c/h2\u003e\n\nAvailable now (`v0.4.0`):\n\n- **Schemaless documents** \u0026mdash; store nested, JSON-like documents with no fixed schema, built from a small, typed [`Value`](./docs/API.md#value) model\n- **Single-file storage** \u0026mdash; the whole database is one file: trivial to ship, copy, and back up\n- **Crash-safe writes** \u0026mdash; every record is length-framed and CRC-32C checked; a write torn by a crash is detected and dropped on the next open, never silently misread\n- **Configurable durability** \u0026mdash; `fsync` on every write, or batch and sync on `flush`; either way the file is never left corrupt\n- **Compaction** \u0026mdash; `compact` reclaims the space left by overwrites and deletes via a crash-safe atomic file swap\n- **Concurrency** \u0026mdash; single-writer, multi-reader; `Db` is `Send + Sync`, so share it across threads behind an `Arc\u003cRwLock\u003cDb\u003e\u003e`\n- **Frozen on-disk format** \u0026mdash; the [format](./docs/FORMAT.md) is stable (version 1); files written by 0.2.0 onward stay readable\n- **Embedded, zero-network** \u0026mdash; runs in-process; no server, no daemon, no external services\n- **Point operations** \u0026mdash; `insert`, `get`, `update`, and `delete` documents by id, plus `flush` for durability\n- **Secondary indexes** \u0026mdash; index any number of document fields; queries also work without an index, so an index is a pure speedup\n- **Field and range queries** \u0026mdash; `find` by an exact field value, `range` over an ordered field\n- **Optional `serde`** \u0026mdash; move documents in and out of JSON, MessagePack, or any serde format\n\nPossible future directions (post-1.0, additive only — the 1.0 API and format do not change):\n\n- **Read cache / memory-mapped reads** \u0026mdash; close the modest point-read gap to memory-mapped engines\n- **Persistent / lazily-rebuilt indexes** \u0026mdash; avoid re-declaring indexes after reopening, via a sidecar file\n\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\n## Installation\n\n```toml\n[dependencies]\nbison-db = \"1.0\"\n\n# With serde support for the document model:\nbison-db = { version = \"1.0\", features = [\"serde\"] }\n```\n\n\u003cbr\u003e\n\n## Quick Start\n\n```rust\nuse bison_db::{Db, Document};\n\nfn main() -\u003e bison_db::Result\u003c()\u003e {\n    // The whole database is a single file.\n    let mut db = Db::open(\"library.bison\")?;\n\n    // Schemaless: set whatever fields you like, of mixed types.\n    let mut album = Document::new();\n    album.set(\"artist\", \"Miles Davis\").set(\"title\", \"Kind of Blue\").set(\"year\", 1959_i64);\n\n    // Insert returns a stable id; read, overwrite, and delete by it.\n    let id = db.insert(album)?;\n    let stored = db.get(id)?.expect(\"just inserted\");\n    assert_eq!(stored.get(\"title\").and_then(|v| v.as_str()), Some(\"Kind of Blue\"));\n\n    db.update(id, { let mut d = Document::new(); d.set(\"title\", \"So What\"); d })?;\n    assert!(db.delete(id)?);\n\n    db.flush()?; // make recent writes durable\n    Ok(())\n}\n```\n\nMore runnable programs live in [`examples/`](./examples): `quick_start`, `user_profiles` (CRUD with nested documents), `secondary_indexes`, `durability`, `compaction`, `session_store` (a realistic indexed store), `crash_recovery`, and `json_interop`.\n\n```bash\ncargo run --example session_store\ncargo run --example secondary_indexes\ncargo run --example durability\ncargo run --example compaction\ncargo run --example crash_recovery\ncargo run --example json_interop --features serde\n```\n\n\u003cbr\u003e\n\n## Querying\n\nIndex any number of fields, then query by exact value or by range. Queries work\nwith or without an index — declaring one only makes them faster.\n\n```rust\nuse bison_db::{Db, Document, Value};\n\nfn main() -\u003e bison_db::Result\u003c()\u003e {\n    let mut db = Db::open(\"people.bison\")?;\n\n    for (name, age) in [(\"ada\", 36_i64), (\"grace\", 45), (\"alan\", 29)] {\n        let mut d = Document::new();\n        d.set(\"name\", name).set(\"age\", age);\n        db.insert(d)?;\n    }\n\n    // Build indexes — there is no cap on how many fields you index.\n    db.create_index(\"name\")?;\n    db.create_index(\"age\")?;\n\n    // Equality: who is named \"ada\"?\n    let ada = db.find(\"name\", \u0026Value::from(\"ada\"))?;        // Vec\u003cDocId\u003e\n\n    // Range: everyone aged 30..=44 (results ordered by age).\n    let thirties_forties = db.range(\"age\", Value::from(30_i64)..=Value::from(44_i64))?;\n\n    assert_eq!(ada.len(), 1);\n    assert_eq!(thirties_forties.len(), 1); // ada (36)\n    Ok(())\n}\n```\n\n\u003cbr\u003e\n\n## Durability\n\nChoose how durable writes are when you open the store. The default,\n`SyncPolicy::Manual`, is fastest: writes are crash-safe (a torn write is never\nmisread), but a power loss can lose the most recent writes that were never\nflushed. `SyncPolicy::Always` `fsync`s after every write, so each one is durable\nthe moment it returns.\n\n```rust\nuse bison_db::{Db, DbOptions, Document, SyncPolicy};\n\nfn main() -\u003e bison_db::Result\u003c()\u003e {\n    // Durable per write — every insert/update/delete fsyncs before returning.\n    let mut db = Db::open_with(\"ledger.bison\", DbOptions::new().sync(SyncPolicy::Always))?;\n    db.insert({ let mut d = Document::new(); d.set(\"entry\", \"debit 100\"); d })?;\n    // No explicit flush needed under Always.\n    Ok(())\n}\n```\n\nEither way the file is never left corrupt: every record is CRC-checked, a crash\ntorn write at the tail is truncated on the next open, and the [on-disk\nformat](./docs/FORMAT.md) is frozen and versioned. See [`docs/FORMAT.md`](./docs/FORMAT.md) for the byte-level layout.\n\n\u003cbr\u003e\n\n## Reclaiming space\n\nThe store is append-only, so overwrites and deletes leave dead records behind.\n`compact` rewrites the file with one record per live document and swaps it in\natomically. Document ids and secondary indexes are preserved.\n\n```rust\n# fn main() -\u003e bison_db::Result\u003c()\u003e {\n# let mut db = bison_db::Db::open(std::env::temp_dir().join(\"readme_compact.bison\"))?;\nlet before = db.stats().file_bytes;\ndb.compact()?;\nlet after = db.stats().file_bytes; // smaller, with the same live data\n# assert!(after \u003c= before);\n# Ok(())\n# }\n```\n\n\u003cbr\u003e\n\n## Concurrency\n\n`Db` follows a single-writer, multi-reader model, like an embedded SQL engine:\nreads take `\u0026self`, writes take `\u0026mut self`. `Db` is `Send + Sync`, so the\nidiomatic way to share one across threads is an `Arc\u003cRwLock\u003cDb\u003e\u003e` — many readers\nconcurrently, or one exclusive writer.\n\n```rust\nuse std::sync::{Arc, RwLock};\nuse bison_db::{Db, Document};\n\n# fn main() -\u003e bison_db::Result\u003c()\u003e {\nlet db = Arc::new(RwLock::new(Db::open(\"shared.bison\")?));\n\n// Writer:\ndb.write().unwrap().insert({ let mut d = Document::new(); d.set(\"k\", 1_i64); d })?;\n\n// Reader on another thread:\nlet snapshot = Arc::clone(\u0026db);\nstd::thread::spawn(move || {\n    let guard = snapshot.read().unwrap();\n    let _ = guard.len();\n});\n# Ok(())\n# }\n```\n\n\u003cbr\u003e\n\n## API Overview\n\nFor the complete reference, see [`docs/API.md`](./docs/API.md).\n\n- [`Db`](./docs/API.md#db) / [`DbOptions`](./docs/API.md#dboptions) \u0026mdash; open the store (with a durability policy); `insert` / `get` / `update` / `delete` / `flush` / `compact`; `create_index` / `find` / `range`\n- [`Document`](./docs/API.md#document) \u0026mdash; the ordered, schemaless record you store\n- [`Value`](./docs/API.md#value) \u0026mdash; a field's content: null, bool, int, float, string, bytes, array, or nested document\n- [`DocId`](./docs/API.md#docid) \u0026mdash; a document's stable primary key\n- [`Error`](./docs/API.md#error) \u0026mdash; the closed set of failures an operation can return\n\n\u003cbr\u003e\n\n## Performance\n\n`bison-db` is an in-process store: there is no network hop and no client/server serialization. Writes are appended sequentially to one file (the access pattern storage hardware serves fastest), and a read is a single hash-index lookup followed by one positional read. Indicative single-threaded figures from `cargo bench` on a developer laptop (Linux, x86_64, Rust 1.95):\n\n| Operation | Time |\n|-----------|------|\n| `insert` a small document | ~0.9 µs |\n| `get` a small document | ~0.36 µs |\n| `update` a small document | ~0.6 µs |\n| `find` by indexed field (in a 10k-doc store) | ~65 ns |\n| `find` by full scan (in a 10k-doc store) | ~1.8 ms |\n\nThe last two rows are the same query with and without an index — the index turns a full scan into a B-tree point lookup (~27,000× here). Numbers are produced by [`benches/bison_bench.rs`](./benches/bison_bench.rs) against a real on-disk store; reproduce them with `cargo bench`.\n\nIn a controlled head-to-head against [`redb`](https://github.com/cberner/redb) (a pure-Rust ACID embedded engine), bison-db is **~1.85× faster on bulk inserts** and **~35% smaller on disk**, while redb is **~1.3× faster on point reads** — an honest split, with bison-db carrying a richer document model on top. See [`docs/PERFORMANCE.md`](./docs/PERFORMANCE.md) for the full method, environment, durability cost, and the reproducible harness in [`benchmarks/`](./benchmarks).\n\n\u003cbr\u003e\n\u003chr\u003e\n\u003cbr\u003e\n\n## Where It Fits\n\n`bison-db` composes the storage primitives into a document store. It builds on:\n\n- [`wal-db`](https://github.com/jamesgober/wal-db) \u0026mdash; durable write-ahead logging and crash recovery\n- [`index-db`](https://github.com/jamesgober/index-db) \u0026mdash; B+tree secondary indexes over document fields\n- [`page-db`](https://github.com/jamesgober/page-db) \u0026mdash; fixed-size paged storage substrate\n- applications \u0026mdash; any Rust app needing a local document store with no server\n\nIt is the first crate in the Bison embedded-database family.\n\n\u003cbr\u003e\n\n## Cross-Platform Support\n\nLinux (x86_64, aarch64), macOS (x86_64, Apple Silicon), and Windows (x86_64) are first-class and verified by the CI matrix.\n\n\u003cbr\u003e\n\n## Contributing\n\nSee [`CONTRIBUTING.md`](./CONTRIBUTING.md) and [`dev/DIRECTIVES.md`](./dev/DIRECTIVES.md). Before a PR: `cargo fmt --all`, `cargo clippy --all-targets --all-features -- -D warnings`, and `cargo test --all-features` must be clean.\n\n\u003cbr\u003e\n\n\u003cdiv id=\"license\"\u003e\n    \u003ch2\u003eLicense\u003c/h2\u003e\n    \u003cp\u003eLicensed under either of\u003c/p\u003e\n    \u003cul\u003e\n        \u003cli\u003e\u003cb\u003eApache License, Version 2.0\u003c/b\u003e \u0026mdash; \u003ca href=\"./LICENSE-APACHE\"\u003eLICENSE-APACHE\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eMIT License\u003c/b\u003e \u0026mdash; \u003ca href=\"./LICENSE-MIT\"\u003eLICENSE-MIT\u003c/a\u003e\u003c/li\u003e\n    \u003c/ul\u003e\n    \u003cp\u003eat your option.\u003c/p\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ch2\u003e\u003c/h2\u003e\n  \u003csup\u003eCOPYRIGHT \u003csmall\u003e\u0026copy;\u003c/small\u003e 2026 \u003cstrong\u003eJAMES GOBER.\u003c/strong\u003e\u003c/sup\u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesgober%2Fbison-db","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesgober%2Fbison-db","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesgober%2Fbison-db/lists"}