{"id":51709813,"url":"https://github.com/libredb/libredb-database","last_synced_at":"2026-07-16T19:04:30.610Z","repository":{"id":367520270,"uuid":"1280900899","full_name":"libredb/libredb-database","owner":"libredb","description":"LibreDB is a small, readable, embeddable, multi-model database. One ordered key-value core, thin model lenses on top.","archived":false,"fork":false,"pushed_at":"2026-07-13T10:53:27.000Z","size":971,"stargazers_count":6,"open_issues_count":17,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-13T12:16:02.392Z","etag":null,"topics":["bun","database","document-database","embedded","embedded-database","key-value","multi-model","relational","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@libredb/libredb","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/libredb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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}},"created_at":"2026-06-26T03:34:34.000Z","updated_at":"2026-07-13T10:52:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/libredb/libredb-database","commit_stats":null,"previous_names":["libredb/libredb-database"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/libredb/libredb-database","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/libredb%2Flibredb-database","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/libredb%2Flibredb-database/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/libredb%2Flibredb-database/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/libredb%2Flibredb-database/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/libredb","download_url":"https://codeload.github.com/libredb/libredb-database/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/libredb%2Flibredb-database/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35555544,"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-16T02:00:06.687Z","response_time":83,"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":["bun","database","document-database","embedded","embedded-database","key-value","multi-model","relational","typescript"],"created_at":"2026-07-16T19:04:29.993Z","updated_at":"2026-07-16T19:04:30.595Z","avatar_url":"https://github.com/libredb.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LibreDB\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/img/01-hero-dark.png\"\u003e\n  \u003cimg alt=\"LibreDB - Multi-model without the magic. One core, three lenses, every line tested.\" src=\"docs/img/01-hero-light.png\" width=\"100%\"\u003e\n\u003c/picture\u003e\n\n**Multi-model without the magic. One core, three lenses, every line tested.**\n\n[![npm version](https://img.shields.io/npm/v/@libredb/libredb.svg)](https://www.npmjs.com/package/@libredb/libredb)\n[![JSR](https://jsr.io/badges/@libredb/libredb)](https://jsr.io/@libredb/libredb)\n[![Docker Hub](https://img.shields.io/docker/v/libredb/libredb?logo=docker\u0026logoColor=white\u0026label=docker%20hub\u0026color=2496ED\u0026sort=semver)](https://hub.docker.com/r/libredb/libredb)\n[![CI](https://github.com/libredb/libredb-database/actions/workflows/ci.yml/badge.svg)](https://github.com/libredb/libredb-database/actions/workflows/ci.yml)\n[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=libredb_libredb-database\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=libredb_libredb-database)\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=libredb_libredb-database\u0026metric=coverage)](https://sonarcloud.io/summary/new_code?id=libredb_libredb-database)\n[![license](https://img.shields.io/npm/l/@libredb/libredb.svg)](./LICENSE)\n[![types: included](https://img.shields.io/badge/types-included-blue.svg)](https://www.typescriptlang.org/)\n[![dependencies: 0](https://img.shields.io/badge/dependencies-0-brightgreen.svg)](./package.json)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/@libredb/libredb)](https://bundlephobia.com/package/@libredb/libredb)\n[![status: early beta](https://img.shields.io/badge/status-early%20beta-orange.svg)](#project-status--roadmap)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/libredb/libredb-database)\n\nLibreDB is a small, readable, embeddable, multi-model database written in TypeScript. It is built on\none idea: a database can be powerful and still be understood by opening its source. A single ordered\nkey-value core handles durability and transactions; key-value, document, and relational APIs are thin\n*lenses* over that one core — not three separate engines. It runs in-memory for tests or file-backed\nfor durability, ships **zero runtime dependencies**, and proves its crash recovery with deterministic\nsimulation testing. Today it is an early beta, aimed at test and development environments — small\nenough to learn how a database actually works, and serious enough to grow into more.\n\n## Highlights\n\n- **One small core, three lenses** — key-value, document, and relational over a single ordered\n  key-value engine (FoundationDB-style), not three engines bolted together.\n- **Multi-model** — raw strings, JSON documents, and schema-validated typed tables in the same\n  database, even the same file.\n- **Readable by design** — the kernel is one file of under a thousand lines, roughly half of it\n  explanatory prose; open the source and learn how a database\n  actually works.\n- **Embeddable, zero dependencies** — `bun add @libredb/libredb` and go; nothing else to install or\n  run.\n- **In-memory or durable** — `open()` for tests, `open({ path })` for a crash-safe, WAL-backed,\n  fsync-on-commit file.\n- **TypeScript-native** — full types shipped, ESM-only, tree-shakeable, under 6 kB min+brotli.\n- **Crash recovery you can trust** — 100% line coverage on the core, plus deterministic simulation\n  testing that tortures the write-ahead log under a simulated crashing filesystem.\n- **Nothing hidden** — queries are plain in-engine scans, errors surface, and costs are obvious (O(n)\n  scans, no secret indexes).\n\n## Quick start\n\n```sh\nbun add @libredb/libredb\n# or: npm install @libredb/libredb\n```\n\nLibreDB is ESM-only, ships zero runtime dependencies, and targets Bun (the development runtime) and\nNode 22+. The same database speaks all three lenses — here they are in one file:\n\n```ts\nimport { open, kv, doc, table } from \"@libredb/libredb\";\n\n// In-memory for tests, or open({ path: \"data.libredb\" }) for a durable, crash-safe file.\nconst db = open();\n\n// 1. Key-value: a durable, ordered, string-keyed map.\nconst cache = kv(db);\ncache.set(\"user:1\", \"Ada\");\ncache.get(\"user:1\"); // \"Ada\"\n\n// 2. Document: a collection of JSON documents under string ids.\nconst logs = doc(db, \"logs\");\nlogs.put(\"l1\", { level: \"info\", message: \"started\", at: 1 });\nlogs.find({ level: \"info\" }).toArray(); // [{ id: \"l1\", doc: { ... } }]\n\n// 3. Relational: a schema-validated, typed table with where / select / join.\nconst users = table(db, \"users\", {\n  primaryKey: \"id\",\n  columns: { id: \"string\", name: \"string\", age: \"number\" },\n});\nusers.insert({ id: \"1\", name: \"Ada\", age: 36 });\nusers.where({ name: \"Ada\" }).select(\"id\", \"age\").toArray(); // [{ id: \"1\", age: 36 }]\n\ndb.close();\n```\n\nEach lens has its own guide: [key-value](./docs/guides/key-value.md) ·\n[document](./docs/guides/document.md) · [relational](./docs/guides/relational.md) ·\n[catalog](./docs/guides/catalog.md).\n\n## Install elsewhere: JSR, CDN, and the browser\n\nLibreDB is the same ESM-only package everywhere; only how you reach it changes.\n\n**JSR** — published to [jsr.io](https://jsr.io/@libredb/libredb) alongside npm:\n\n```sh\nbunx jsr add @libredb/libredb\n# or: npx jsr add @libredb/libredb / deno add jsr:@libredb/libredb\n```\n\n**CDN** — every release is served from the npm registry by the usual CDNs. Pin a version:\n\n```ts\nimport { open, kv } from \"https://esm.sh/@libredb/libredb@0.2.2\";\n```\n\n**Browser** — a dedicated entry that imports nothing from `node:`, so it bundles for the browser\ncleanly. Its `open` carries no default filesystem: an in-memory database works anywhere, and a\npath-backed open takes a filesystem you inject (e.g. the OPFS adapter shown below).\n\n```ts\nimport { open, kv } from \"@libredb/libredb/browser\";\n\nconst db = open(); // in-memory\nkv(db).set(\"greeting\", \"hello\");\n```\n\nFor durable storage in the browser, run inside a Web Worker and back the database with an OPFS sync\naccess handle (the kernel stays synchronous — no async core):\n\n```ts\nimport { open, opfsFileSystem } from \"@libredb/libredb/browser\";\n\nconst root = await navigator.storage.getDirectory();\nconst file = await root.getFileHandle(\"app.libredb\", { create: true });\nconst handle = await file.createSyncAccessHandle();\nconst db = open({ path: \"app.libredb\", fs: opfsFileSystem(handle) });\n```\n\nA browser-targeting bundler also resolves the browser build from the main `@libredb/libredb` entry\nvia the package's `browser` export condition. Note that TypeScript usually still resolves the Node\ntypes for that entry (where `fs` is optional) unless it is configured for the `browser` condition\n(`customConditions`). To get the browser-specific typing — `fs` required when `path` is given — and\nkeep types in step with the runtime, import the explicit `@libredb/libredb/browser` subpath.\n\n**Using LibreDB in a web app with no backend?** The full guide —\nin-memory vs durable (OPFS) storage, the Web Worker pattern, and React / Vite /\nNext.js / Astro setup — is in [`docs/BROWSER.md`](./docs/BROWSER.md).\n\n## Command-line tool\n\nThe package ships a `libredb` bin for inspecting and editing `.libredb` files — no code required:\n\n```sh\nnpx libredb inspect data.libredb          # namespaces, kinds, and table schemas\nnpx libredb stats data.libredb            # file size and namespace counts\nnpx libredb get data.libredb user:1       # print one value\nnpx libredb scan data.libredb user:       # print key=value under a prefix\nnpx libredb set data.libredb user:1 Ada   # set a key\nnpx libredb delete data.libredb user:1    # remove a key\nnpx libredb import data.libredb seed.json # bulk-set from a JSON object, atomically\n```\n\nRead commands open the file read-only, so inspection never mutates it. Write commands take an\nadvisory `\u003cpath\u003e.lock` to refuse a second concurrent writer. A lock left by a writer that crashed on\nthe same host is reclaimed automatically — no flag needed. Use `--force` only for a lock whose\nholder cannot be verified (an anonymous lock or one written on another host); it refuses a holder\nthat is verifiably alive, so it cannot knowingly admit two live writers. The remaining risk is the\nunverifiable case: a live writer on another machine sharing the file can still be forced past, which\ncan corrupt the file.\n\nPrefer a standalone binary with no Node or Bun installed? Each release attaches self-contained\nexecutables (Linux and macOS on x64 and arm64; Windows on x64) with `.sha256` checksums on its\n[GitHub Release](https://github.com/libredb/libredb-database/releases). Or build one locally with\n`bun run compile`.\n\nOr run the CLI from a container (multi-arch, published to GHCR and Docker Hub) — mount your data and\npass a command:\n\n```sh\ndocker run --rm -v \"$PWD:/data\" ghcr.io/libredb/libredb inspect /data/app.libredb\n# or from Docker Hub: docker run --rm -v \"$PWD:/data\" libredb/libredb inspect /data/app.libredb\n```\n\nThe same multi-arch image is published to both registries:\n[Docker Hub](https://hub.docker.com/r/libredb/libredb) and\n[GHCR](https://github.com/libredb/libredb-database/pkgs/container/libredb). It is a CLI shell, not a\nserver: LibreDB stays an embedded, in-process database.\n\nFull references: the [CLI](./docs/CLI.md) (every command, safety model, exit codes), the\n[standalone binaries](./docs/BINARY.md) (download + verify), and the [Docker image](./docs/DOCKER.md).\n\n## How it works: one core, three lenses\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/img/02-lenses-dark.png\"\u003e\n  \u003cimg alt=\"One core, three lenses: kv, document, and relational APIs over a single ordered key-value core (core.ts), reaching disk through one FileSystem seam.\" src=\"docs/img/02-lenses-light.png\" width=\"100%\"\u003e\n\u003c/picture\u003e\n\nLibreDB has a single ordered byte key-value kernel (`src/core.ts`). Key-value, document, and relational\nare thin typed *lenses* over it — three faces of the same store. A relational table is physically a\nJSON document collection, which is physically ordered key-value entries built from composite keys like\n`users:42`. The kernel reaches the disk through one injectable filesystem seam, which is also what\nmakes deterministic crash testing possible.\n\n```mermaid\nflowchart TB\n    subgraph consumers [Consumers]\n        App[Your app]\n        Studio[LibreDB Studio]\n        Platform[LibreDB Platform]\n    end\n\n    API[\"Public API · index.ts\u003cbr/\u003eopen · kv · doc · table · catalog\"]\n\n    subgraph lenses [Lenses and shared edges - open, fast to contribute]\n        KV[kv\u003cbr/\u003estrings]\n        DOC[document\u003cbr/\u003eJSON]\n        REL[relational\u003cbr/\u003etyped tables]\n        CAT[catalog\u003cbr/\u003eself-describing registry]\n    end\n\n    CORE[\"core.ts - THE KERNEL\u003cbr/\u003eordered byte KV · serializable txns · WAL · crash recovery\"]\n    FS[\"FileSystem seam\u003cbr/\u003enode:fs adapter - or SimFS for crash tests\"]\n\n    App --\u003e API\n    Studio --\u003e API\n    Platform --\u003e API\n    API --\u003e KV\n    API --\u003e DOC\n    API --\u003e REL\n    API --\u003e CAT\n    REL --\u003e DOC\n    KV --\u003e CORE\n    DOC --\u003e CORE\n    REL --\u003e CORE\n    CAT --\u003e CORE\n    CORE --\u003e FS\n```\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/img/03-trust-dark.png\"\u003e\n  \u003cimg alt=\"Open at the edges, guarded at the core: lenses, query surface, catalog, adapters, Studio, and docs are open to contribute; core.ts is guarded with 100% line coverage, deterministic crash tests, and heavy review - everything reaches the store through one narrow transact() port.\" src=\"docs/img/03-trust-light.png\" width=\"100%\"\u003e\n\u003c/picture\u003e\n\n**The file boundary is the trust boundary.** Below the line (`core.ts`) is guarded: heavy review and\ndeterministic crash tests, because a bug there corrupts data. Above the line (lenses, query, catalog)\nis open and fast to contribute to, because the worst a bug can do is present a bad *view* — it reaches\nthe store only through one narrow `transact` port. For the full tour, read\n[`ARCHITECTURE.md`](./ARCHITECTURE.md).\n\n## When to use LibreDB\n\n**Reach for it when you want to:**\n\n- Back tests and local development with a real, durable, multi-model store instead of mocks.\n- Embed a small database directly in a TypeScript / Bun / Node app with zero infrastructure.\n- Learn how a database works by reading — and hacking — a small, honest codebase.\n- Prototype across key-value, document, and relational shapes without standing up three systems.\n\n**Do not use it (yet) when you need:**\n\n- A hardened production datastore at scale — it is an **early beta**; today's beachhead is test/dev.\n- Secondary indexes or a query planner — queries are O(n) scans by design in v1 (on the roadmap).\n- Concurrent multi-process access, replication, or a networked client/server — it is embedded,\n  in-process, and strictly single-writer (a second `open()` on the same file is refused by an\n  exclusive lock rather than silently corrupting it).\n- SQL wire compatibility or an existing-driver ecosystem.\n\nThese limits are deliberate v1 scope, not hidden gaps — LibreDB's strength comes from what it refuses.\nSee the [Manifesto](./MANIFESTO.md).\n\n## Reliability\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/img/04-reliability-dark.png\"\u003e\n  \u003cimg alt=\"Crash recovery you can trust: a length-framed, CRC-32-checksummed write-ahead log fsync'd before commit; recovery truncates the last un-fsync'd record so what remains is always a valid committed prefix - proven by deterministic simulation testing.\" src=\"docs/img/04-reliability-light.png\" width=\"100%\"\u003e\n\u003c/picture\u003e\n\nA transaction that returns has been written to a length-framed, CRC-32-checksummed write-ahead log and\n`fsync`'d *before* the commit becomes visible — so on a healthy disk a committed write survives a\ncrash, and a crash can only ever damage the last, un-fsync'd record (which recovery detects,\ntruncates, and reports). The failure modes *outside* the clean-crash model are handled explicitly, not\nassumed away: a failed append/fsync latches the database instead of writing past a torn record, a\nsecond writer is refused by an exclusive open lock, a file that is not a LibreDB database is refused\nuntouched (the `LRDB` header), mid-log corruption refuses to open rather than silently truncating, and\na short read is an IO error, never data loss. This is not just asserted: the crash/recovery path is\nproven by **deterministic simulation testing** — the real engine against a seeded in-memory filesystem\nthat tears, corrupts, errors, and crashes the log on command — plus a binary round-trip fuzz.\n\n```sh\nbun run test    # includes a bounded 50-seed DST run and the fault-injection suites\n```\n\nThe precise durability contract and the DST walkthrough are in\n[`docs/RELIABILITY.md`](./docs/RELIABILITY.md).\n\n## Performance envelope\n\nHonesty about scale (comprehension is the budget in v1, not throughput):\n\n- **The whole store lives in memory** as one sorted array; the file on disk is the append-only log\n  that rebuilds it on open. The practical ceiling is data that comfortably fits in RAM — the test/dev\n  beachhead, not a server working set.\n- **Each `transact()` copies the store** before applying writes, so a per-row auto-commit loop is\n  quadratic in store size and will look hung on large seeds. **Wrap bulk loads in one `transact()`**\n  (or use `libredb import`, which already does): one copy, one fsync, one record for the whole batch.\n- **No secondary indexes**: a `find`/`where` is an O(n) scan by design in v1.\n- **The log grows without bound** until compaction lands (tracked in\n  [#12](https://github.com/libredb/libredb-database/issues/12)); reopening replays the whole log.\n\n## Documentation\n\n| Topic | Where |\n|-------|-------|\n| Lens guides (kv, document, relational, catalog) | [`docs/guides/`](./docs/guides/) |\n| Browser — embed in a web app with no backend (in-memory + OPFS) | [`docs/BROWSER.md`](./docs/BROWSER.md) |\n| CLI — inspect and edit `.libredb` files (`npx libredb`) | [`docs/CLI.md`](./docs/CLI.md) |\n| Standalone binaries — download and run, no Node/Bun | [`docs/BINARY.md`](./docs/BINARY.md) |\n| Docker — run the CLI from a container | [`docs/DOCKER.md`](./docs/DOCKER.md) |\n| Architecture — the guided tour under the hood | [`ARCHITECTURE.md`](./ARCHITECTURE.md) |\n| Design — the locked engineering decisions | [`docs/DESIGN.md`](./docs/DESIGN.md) |\n| Reliability — durability and crash recovery | [`docs/RELIABILITY.md`](./docs/RELIABILITY.md) |\n| Manifesto — what LibreDB is and refuses to be | [`MANIFESTO.md`](./MANIFESTO.md) |\n| LibreDB Studio integration | [`docs/STUDIO.md`](./docs/STUDIO.md) |\n\n## Project status \u0026 roadmap\n\nLibreDB is an **early beta** (`0.1.x`). The architecture is in place, every line of the core is\ntested, and the durability contract above is enforced — but the API may still change before 1.0, and\nthe recommended home is still test/dev data.\n\n- **Done:** the ordered key-value kernel (transactions, WAL with a versioned on-disk header, crash\n  recovery that refuses corruption and foreign files, an IO-failure latch, an exclusive open lock);\n  the key-value, document, and relational lenses; the self-describing catalog; typed `LibreDbError`\n  codes; the DST harness with IO-fault injection and binary fuzz; 100% line/function/statement\n  coverage.\n- **Next:** secondary indexes and a richer query surface; more query operators; additional lenses;\n  WAL compaction/checkpointing\n  ([#12](https://github.com/libredb/libredb-database/issues/12)); real-browser OPFS verification\n  ([#10](https://github.com/libredb/libredb-database/issues/10)).\n\n## The LibreDB family\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/img/05-family-dark.png\"\u003e\n  \u003cimg alt=\"The LibreDB family: LibreDB (the database, this repo), LibreDB Studio (the open-source IDE for every database), and LibreDB Platform (the managed, team-oriented form of data) - three products, one access-model spine.\" src=\"docs/img/05-family-light.png\" width=\"100%\"\u003e\n\u003c/picture\u003e\n\nLibreDB is the database in a three-product family that shares one access-model spine:\n\n- **LibreDB** — the database (this repository).\n- **LibreDB Studio** — the open-source IDE for *every* database (Postgres, MySQL, MongoDB, Redis, and\n  more). LibreDB is one database it supports natively, not a requirement.\n- **LibreDB Platform** — the managed, team-oriented form of data.\n\n## Contributing\n\nContributions are welcome. LibreDB is open at the edges and guarded at the durability core — see\n[`CONTRIBUTING.md`](./CONTRIBUTING.md) for how to get set up, the `bun run gate` bar every change must\npass, and where contributions land fastest. Please also read the\n[`CODE_OF_CONDUCT.md`](./CODE_OF_CONDUCT.md).\n\n## Security\n\nTo report a security vulnerability, see [`SECURITY.md`](./SECURITY.md) — please do not open a public\nissue.\n\n## License\n\nOpen source and free under the [MIT License](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flibredb%2Flibredb-database","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flibredb%2Flibredb-database","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flibredb%2Flibredb-database/lists"}