libredb is a small command-line tool for inspecting and editing .libredb
files — no code required. It is built on the public API, ships with the package,
and has zero dependencies (it uses Node/Bun's built-in parseArgs).
Because LibreDB is an embedded database, the CLI is a local tool — like
sqlite3 or cat: it opens the file path you give it, on your machine. There is
no server and no daemon.
Three ways to run the exact same CLI: via the package (
npx libredb, below), a standalone binary (no Node/Bun needed), or a Docker image. The command set in this document applies to all three.
# one-off, via the published package (no install)
npx libredb <command> <path> [args] # npm
bunx libredb <command> <path> [args] # bun
# or install it
npm install -g @libredb/libredb # then: libredb <command> ...Run with no arguments (or --help) to print usage:
$ libredb
libredb - inspect and edit .libredb files
Usage:
libredb inspect <path> List each namespace, its kind, and table schemas
libredb stats <path> Summarize the file: size and namespace counts
libredb get <path> <key> Print the value stored at a key
libredb scan <path> <prefix> Print key=value for every key under a prefix
libredb set <path> <key> <value> Set a key to a value
libredb delete <path> <key> Remove a key
libredb import <path> <file.json> Bulk-set keys from a JSON object (one atomic commit)
Options:
--force Remove a write lock whose holder is no longer alive
--raw Print values verbatim (default escapes control characters)These open the file read-only and never modify it (see Safety).
Lists the file size and each catalogued namespace with its kind, plus the schema for relational tables.
$ libredb inspect app.libredb
app.libredb 412 bytes
logs document
people relational {"primaryKey":"id","columns":{"id":"string","name":"string"}}Note: only
documentandrelationalnamespaces are catalogued; plain key-value pairs are the raw layer and are not listed here. A file holding only kv data prints(no catalogued namespaces)— its keys are still readable withget/scan.
$ libredb stats app.libredb
app.libredb 412 bytes 2 namespaces
kv: 0 document: 1 relational: 1$ libredb get app.libredb user:1
AdaExits non-zero (1) with key not found: <key> if the key is absent.
Prints key=value, one per line, in the kernel's ascending byte order.
$ libredb scan app.libredb user:
user:1=Ada
user:2=GraceThese take an advisory lock (see Safety) and commit through the WAL.
$ libredb set app.libredb user:1 Ada
set user:1 (1 changed)$ libredb delete app.libredb user:1
delete user:1 (1 removed) # "(0 removed)" if the key did not existReads a JSON object of string values and sets every pair in a single transaction — the whole load lands, or (on a crash mid-write) none of it does.
$ cat seed.json
{ "user:1": "Ada", "user:2": "Grace", "color": "teal" }
$ libredb import app.libredb seed.json
import 3 keysThe JSON must be an object whose values are all strings; anything else is a usage error.
The CLI touches real database files, so it is deliberately careful:
- Reads never mutate the file. Opening a database runs crash recovery, which
would normally truncate a torn tail — a write. Read commands
(
inspect/stats/get/scan) open through a read-only filesystem adapter: recovery drops a torn tail in memory only; the bytes on disk are left exactly as found. - A wrong path cannot destroy a file. Opening a file that is not a LibreDB
database (a typo, a text file) fails with a clear error and leaves the file
byte-for-byte untouched — the on-disk
LRDBheader is checked before anything is written. - Writes hold the exclusive open lock. The library itself locks the database
on open (
<path>.lock, recording the holder's pid and host), so a second writer — this CLI against a live app, or two CLI invocations — fails loudly instead of silently corrupting the file. A lock whose holder is verifiably dead is reclaimed automatically;--forceadditionally removes a lock that cannot be verified (for example one from another machine), but refuses a verifiably live holder and refuses to delete a file that is not a libredb lock. - Output is escaped by default.
get/scanprint stored values with control characters escaped (\x1b,\x07, ...), so a value containing terminal escape sequences cannot clear your screen, retitle your terminal, or write your clipboard when you inspect an untrusted file. Pass--rawfor the exact bytes. - Reserved keys are refused. Writes reject keys in LibreDB's reserved
namespace (the
\x00-prefixed catalog space), so the CLI cannot corrupt the catalog or another lens's layout. - Bulk imports are atomic.
importcommits all keys in one transaction.
The WAL is the database: one .libredb file holds everything, so backup is a
file copy — with one rule.
-
Backup: copy the file while no writer has it open (no
<path>.lockpresent, or only your own closed session). A copy taken mid-write can split a record in half; the copy would then open only up to the split.cp app.libredb backup/app-$(date -u +%Y%m%d).libredb -
Restore: copy the file back and open it — recovery replays it like any reopen. Nothing else to do.
-
Export as text:
libredb scan <path> ""is not supported (an empty prefix is refused); scan per namespace prefix, or use the programmatic lenses for a structured export. A first-classexportcommand is on the roadmap.
| Code | Meaning | Examples |
|---|---|---|
0 |
Success | a read/write completed |
1 |
Runtime error | file not found, get on a missing key, lock held by another writer |
2 |
Usage error | unknown command/option, missing argument, malformed import JSON, reserved key |
This makes the CLI scriptable — e.g. in CI:
libredb get app.libredb migration:done >/dev/null 2>&1 || libredb set app.libredb migration:done "$(date -u +%FT%TZ)"get/scan/set/delete/importoperate on the key-value layer (UTF-8 string keys and values).inspect/statsread the catalog for the richer document/relational view.- There is no interactive
repl(it was intentionally left out for now). - The CLI is one of three identical front-ends — see the standalone binary and Docker image for the same commands without a Node/Bun install.
- For the programmatic API behind these commands, see the lens guides.