CLI Reference¶
The Rust CLI is implemented in crates/decentdb-cli and shipped as the decentdb binary.
Most commands take --db=<path>. Use :memory: for an ephemeral in-memory database.
Commands¶
version¶
exec¶
Execute one or more SQL statements.
Supported options: - --params=<type:value> repeatable positional parameters (int:1, float:1.5, bool:true, text:hello, blob:deadbeef, timestamp:1700000000, null) - --format=<json|csv|table> output format, default json - --checkpoint checkpoint after execution, or checkpoint-and-exit if --sql is omitted - --openClose open and close the database without executing SQL - --dbInfo print storage info and exit - --noRows discard result rows and report only the affected row count - --cachePages=<n> cache size in 4KB pages - --cacheMb=<n> cache size in megabytes, overrides --cachePages - --as-of=<snapshot-name> execute read-only SQL against a named snapshot - --as-of-lsn=<lsn> execute read-only SQL against a retained WAL LSN - --branch=<branch> execute against a branch - --allow-extension=<name@sha256:hash> allow an installed and enabled Lua extension package to execute on this connection; may be repeated - --allow-unsigned-extensions development-only override that allows unsigned installed Lua packages to execute without a hash allowlist
--as-of and --as-of-lsn are read-only time-travel modes. Mutating SQL, transaction control, PRAGMA commands, and --checkpoint are rejected in this mode.
repl¶
Interactive SQL shell with: - multi-line input - persistent history in ~/.decentdb_history - transaction-aware prompt state
decentdb repl --db=<path> [--format=<json|csv|table|markdown>] [--allow-extension=<name@sha256:hash>]
Special commands: - help aliases: help, \?, /?, /help, \help, .help - quit aliases: .quit, .exit, \q - schema inspection: .tables, .dt, .d <table>, .schema [object], .indexes [table], .views - output controls: .mode, .headers, .nullvalue, .width, .timer - file workflows: .read, .output, .once, .import, .export - query helpers: .explain, .plan, .explain-analyze, .param - session helpers: .g, .s, .branch, .checkout
See Interactive SQL Shell for the full user guide.
extension¶
Validate, test, install, enable, disable, inspect, and purge sandboxed Lua extension packages.
decentdb extension validate <package-dir> [--allow-unsigned] [--trust-extension=<name@sha256:hash>] [--format=<json|table>]
decentdb extension test <package-dir> [--allow-unsigned] [--trust-extension=<name@sha256:hash>] [--format=<json|table>]
decentdb extension install --db=<path> <package-dir> [--allow-unsigned] [--trust-extension=<name@sha256:hash>] [--format=<json|table>]
decentdb extension list --db=<path> [--format=<json|table>]
decentdb extension show --db=<path> <name> [--format=<json|table>]
decentdb extension enable --db=<path> <name> [--format=<json|table>]
decentdb extension disable --db=<path> <name> [--format=<json|table>]
decentdb extension purge --db=<path> <name> --confirm [--format=<json|table>]
decentdb extension dependencies --db=<path> [--format=<json|table>]
decentdb extension rebuild --db=<path> <name> [--format=<json|table>]
Trust entries use name@sha256:<hash> or name@sha256:<hash>@<key_id>@<public_key>. Public keys and signatures use the same base64:<value> or hex:<value> encoding accepted by the Rust API.
validate and install reject unsigned packages unless --allow-unsigned is present. exec and repl do not run enabled Lua code unless the connection was opened with --allow-extension for the exact package hash or with the development-only --allow-unsigned-extensions override.
See Lua Extensions for package authoring, manifest, trust, and sandbox details.
serve¶
Start a local HTTP API and lightweight Web Console for a database.
Supported options: - --host=<host> bind host, default 127.0.0.1 - --port=<port> bind port, default 7373 - --read-only reject mutating SQL - --open open the default browser - --max-result-rows=<n> maximum rows returned per result set, default 1000 - --query-timeout=<duration> query timeout reporting limit, default 30s - --max-body-size=<size> maximum request body size, default 4mb - --max-concurrent-requests=<n> concurrent request cap, default 32 - --busy-timeout=<duration> busy timeout configuration, default 5s - --token-env=<name> environment variable containing the bearer token - --show-token print the bearer token for API clients/debugging - --no-auth disable auth for localhost-only debugging - --cors-origin=<origin> allow one explicit CORS origin - --log-format=<text|json> request log format, default text
The default localhost workflow uses transparent ephemeral auth. The Web Console receives the token in the initial local page; API calls without the token are rejected. Non-localhost binding requires --token-env, and --no-auth is accepted only for localhost binding.
See Built-In Web Console for the full user guide and HTTP API routes.
import¶
Import CSV data into a table using the bulk-load path.
Current Rust CLI scope: CSV import only.
export¶
Export a table as CSV or JSON.
bulk-load¶
Bulk load CSV data with explicit bulk-load options.
Supported options: - --batchSize=<n> - --syncInterval=<n> - --disableIndexes - --noCheckpoint
checkpoint¶
save-as¶
Write a checkpointed snapshot into a new on-disk database file.
snapshot¶
Manage named time-travel snapshots. A named snapshot records the current durable main state and keeps the required history retained until the snapshot is deleted.
decentdb snapshot create --db=<path> --name=<snapshot> [--format=<json|table>]
decentdb snapshot list --db=<path> [--format=<json|table>]
decentdb snapshot delete --db=<path> --name=<snapshot> [--format=<json|table>]
decentdb exec --db=<path> --as-of=<snapshot> --sql="SELECT ..."
Snapshot rows include name, snapshot_lsn, created_at_micros, branch_id, and head_id.
branch¶
Manage branch metadata and branch state. Branch creation is metadata-only after the source state is checkpointed into a stable branch base.
decentdb branch create --db=<path> --name=<branch> [--from=<main|branch|snapshot|head>] [--format=<json|table>]
decentdb branch list --db=<path> [--format=<json|table>]
decentdb branch commit --db=<path> --name=<branch> --message=<message> [--format=<json|table>]
decentdb branch log --db=<path> --name=<branch> [--format=<json|table>]
decentdb branch diff --db=<path> --left=<main|branch|snapshot|head> --right=<main|branch|snapshot|head> [--format=<json|table>]
decentdb branch restore --db=<path> --name=<branch> --to=<branch|snapshot|head> (--dry-run|--confirm) [--format=<json|table>]
decentdb branch merge --db=<path> --source=<branch> --target=<main|branch> (--dry-run|--confirm) [--format=<json|table>]
decentdb branch rename --db=<path> --name=<branch> --new-name=<new-name> [--format=<json|table>]
decentdb branch delete --db=<path> --name=<branch> [--format=<json|table>]
decentdb exec --db=<path> --branch=<branch> --sql="SELECT ..."
decentdb repl --db=<path> --branch=<branch>
Branch rows include name, branch_id, current_head_id, base_head_id, created_at_micros, and updated_at_micros.
Branch-local writes are isolated from main until an explicit merge. Diff and merge operate on primary-key tables; unsupported schema/table cases are reported as conflicts instead of being applied implicitly. restore currently moves a non-main branch head to a branch, snapshot, or head target.
migrate¶
Check a database file and assist in migrating unsupported legacy formats. Currently, this command detects the source version and provides a helpful message explaining the manual logical dump/restore path if the engine cannot natively upgrade it.
info¶
Show storage-level information.
describe¶
Describe one table, including column flags and foreign key references.
list-tables¶
list-indexes¶
list-views¶
dump¶
Dump the current catalog and table contents as deterministic SQL.
dump-header¶
Decode and print the fixed page-1 header.
rebuild-index¶
rebuild-indexes¶
completion¶
Emit a small static shell completion script.
stats¶
Show page and cache sizing information.
vacuum¶
Checkpoint and rewrite the database into a new output file.
verify-header¶
Open the database, validate the fixed header, and print the decoded fields.
verify-index¶
Rebuild a named index logically and compare entry counts against the current runtime copy.
doctor (new in v2.3)¶
Run a diagnostic health check against a database file. Doctor is read-only by default and does not mutate the database unless --fix is present.
Supported options:
--format=<json|markdown>output format, defaultmarkdown--checks=<all|header,storage,wal,fragmentation,schema,statistics,indexes,compatibility>limit checks to selected categories, defaultall--verify-index=<name>repeatable, run expensive logical verification for named indexes-
--verify-indexesrun expensive logical verification for all indexes up to--max-index-verify -
--max-index-verify=<n>safety cap for--verify-indexes, default32 --fail-on=<info|warning|error>minimum severity that makes the process exit non-zero, defaulterror--include-recommendations[=true|false]include safe recommendation text and commands, defaulttrue--path-mode=<absolute|basename|redacted>controls path rendering in output, defaultabsolute--fixapply v1 auto-fixable actions after diagnosis, then re-run diagnosis
Exit codes:
| Code | Meaning |
|---|---|
| 0 | No findings, or findings below --fail-on threshold |
| 1 | Unexpected error (invalid args, engine failure) |
| 2 | Findings at or above --fail-on threshold |
Basic Markdown example:
Sample output:
# DecentDB Doctor Report
## Status
Overall status: WARNING
## Database
| Field | Value |
|---|---|
| Path | my.ddb |
| Format version | 10 |
| Page size | 4096 |
...
## Summary
| Severity | Count |
|---|---:|
| Error | 0 |
| Warning | 1 |
| Info | 2 |
## Findings
### WARNING wal.large_file -- WAL file is large relative to the database
...
JSON / CI example:
The JSON output includes schema_version, mode, status, database, summary, pre_fix_findings, findings, fixes, and collected objects. This format is the stable integration surface for CI pipelines and tooling.
Index verification example:
Expensive verification is always opt-in. Default runs do not verify any indexes.
Fix mode example:
When --fix is present, doctor:
- Collects diagnostic findings.
- Plans eligible fixes from the v1 fix action catalog.
- Applies fixes in deterministic order.
- Re-collects facts and re-runs checks.
- Reports
mode="fix",pre_fix_findings,findings, andfixes.
tracing (new in v2.11)¶
Query runtime tracing views for slow queries, lock waits, sessions, index usage, Doctor findings, and safe fix plans. Tracing is disabled by default and must be enabled through DbConfig::tracing at open time.
Supported views:
sessions— active session stateslow_queries— captured slow query eventslock_waits— captured lock-wait eventsindex_usage— per-index read/write countersdoctor_findings— merged static and runtime advisor findingsfix_plan— safe-to-apply fix plans
Supported options:
--format=<json|table|markdown>output format, defaultjson--resetclear the selected trace buffer after displaying it
Examples:
plan-cache (new in 2.13.0)¶
Inspect or reset the connection-local plan cache. The plan cache is enabled by default and reduces redundant parse, resolve, and planner work for repeated prepared statements within a Db handle. See design/_archive/WIN_QUERY_PLAN_CACHING_AND_STATEMENT_REUSE.md and ADR 0190-0194.
decentdb plan-cache stats --db=<path> [--format=<json|table|markdown>]
decentdb plan-cache list --db=<path> [--format=<json|table|markdown>]
decentdb plan-cache reset --db=<path>
Subcommands:
stats— displaysys.plan_cache_summary(one row, aggregate counters and the configured memory budget)list— displaysys.plan_cache(one row per cached entry)reset— executePRAGMA flush_plan_cacheon a writer connection and exit
Examples:
# Query slow queries as JSON
decentdb tracing --db=my.ddb --view=slow_queries
# Query lock waits as a table
decentdb tracing --db=my.ddb --view=lock_waits --format=table
# Query index usage and reset the buffer
decentdb tracing --db=my.ddb --view=index_usage --reset
# Query doctor findings (merged static + runtime)
decentdb tracing --db=my.ddb --view=doctor_findings
# Query safe fix plans
decentdb tracing --db=my.ddb --view=fix_plan --format=table
v1 auto-fixable findings:
| Fix action | Trigger finding | Precondition |
|---|---|---|
fix.checkpoint | wal.large_file | No active readers |
fix.rebuild_stale_index | schema.index_not_fresh | Index still exists |
fix.rebuild_invalid_index | index.verify_failed | Verification was requested in the same run |
v1 non-auto-fixable findings (recommendations only):
header.unreadabledatabase.open_failedcompatibility.format_version_unknownwal.many_versionswal.long_readers_presentwal.reader_warnings_recordedwal.shared_enabledfragmentation.highfragmentation.moderateschema.no_user_tablesschema.many_indexes_on_tableindex.verify_errorindex.verify_skipped_limit
Fragmentation is deliberately not auto-fixed because the safe vacuum workflow writes a separate output database. Use decentdb vacuum for that case.
Recommendation safety:
- Doctor suggests safe actions by default (e.g., checkpoint commands).
- When
--fixis present, only the explicit v1 fix action catalog is executed. - Doctor never overwrites or replaces the source database.
- No destructive operations (source-overwriting vacuum, unsafe compaction) are performed.
Sync commands¶
The sync command group manages local-first replication state. It covers replica initialization, peer and scope catalogs, batch export/import, HTTP run transport, conflict inspection, journal pruning, and operational reporting.
Most sync commands emit JSON for machine consumption and tables/key-value rows for human inspection. Use --format json when you need stable downstream parsing.
sync init / enable / disable / status / pending¶
decentdb sync init --db=<path> --replica-id=<replica>
decentdb sync enable --db=<path>
decentdb sync disable --db=<path>
decentdb sync status --db=<path> [--format=<json|table>]
decentdb sync pending --db=<path> [--since=<n>] [--limit=<n>] [--format=<json|table>]
sync initinitializes the replica ID, enables sync capture, and opens the durable journal sidecar.- The database file must already exist. Create it first with a normal command such as
decentdb exec --db=app.ddb --sql="CREATE TABLE ..."if needed. sync enable/sync disabletoggle capture without changing the replica ID.sync statusprintsenabled,replica_id,next_sequence,journal_path, andjournal_size_bytes.sync pendingshows journal records after a sequence watermark.
Example:
decentdb sync init --db=app.ddb --replica-id=node-a
decentdb sync status --db=app.ddb --format=table
decentdb sync pending --db=app.ddb --since=0 --limit=5 --format=json
Expected sync status JSON shape:
{
"enabled": true,
"replica_id": "node-a",
"next_sequence": 2,
"journal_path": "app.ddb.sync-journal",
"journal_size_bytes": 512
}
sync export / import¶
decentdb sync export --db=<path> --since=<n> --output=<batch.json> [--limit=<n>] [--format=json]
decentdb sync import --db=<path> --input=<batch.json>
sync exportwrites a JSONSyncChangeBatchfile.sync importreads that batch file and applies it locally.sync exportcurrently supports JSON only.
Example:
decentdb sync export --db=app-a.ddb --since=0 --limit=100 --output=out.batch.json
decentdb sync import --db=app-b.ddb --input=out.batch.json
Expected sync import summary:
sync peer¶
decentdb sync peer add --db=<path> --name=<peer> --endpoint=<http-or-https> [--token-env=<ENV>] [--format=<json|table>]
decentdb sync peer remove --db=<path> --name=<peer> [--format=<json|table>]
decentdb sync peer list --db=<path> [--format=<json|table>]
endpointmust start withhttp://orhttps://.token-envstores the environment variable name, not the secret value.
Example:
decentdb sync peer add --db=app.ddb --name=central --endpoint=http://127.0.0.1:43123
decentdb sync peer list --db=app.ddb --format=table
sync scope¶
decentdb sync scope create --db=<path> --name=<scope> --include=<table1,table2> [--row-filter=<expr>] [--format=<json|table>]
decentdb sync scope drop --db=<path> --name=<scope> [--format=<json|table>]
decentdb sync scope list --db=<path> [--format=<json|table>]
decentdb sync scope bind --db=<path> --peer=<peer> --scope=<scope> [--format=<json|table>]
decentdb sync scope unbind --db=<path> --peer=<peer> [--format=<json|table>]
decentdb sync scope bindings --db=<path> [--format=<json|table>]
includeis a comma-separated list of table names.row-filteris validated at create time.sync scope unbindremoves the current binding for the peer.
Example:
decentdb sync scope create --db=app.ddb --name=tenant_42 --include=accounts,orders --row-filter="tenant_id = 42"
decentdb sync scope bind --db=app.ddb --peer=central --scope=tenant_42
decentdb sync scope bindings --db=app.ddb --format=table
sync run / serve¶
decentdb sync run --db=<path> --peer=<peer> [--direction=<push|pull|both>] [--limit=<n>] [--retries=<n>] [--conflict-policy=<record|stop|last-writer-wins|origin-priority>] [--format=<json|table>]
decentdb sync serve --db=<path> --bind=<host:port> [--scope=<scope>] [--token-env=<ENV>] [--conflict-policy=<record|stop|last-writer-wins|origin-priority>] [--ready-file=<path>] [--max-requests=<n>]
sync runuses the registered peer endpoint and the peer-to-scope binding.sync serveis a dev/test HTTP endpoint. It is not a hardened public server.directiondefaults toboth.limitcontrols batch size per phase.retriesapplies to retryable HTTP failures.
Example:
decentdb sync run --db=app.ddb --peer=central --direction=both --format=table
decentdb sync serve --db=app.ddb --bind=127.0.0.1:0 --max-requests=3
Expected sync run table output includes:
peer_namedirectionremote_replica_idretry_countpushed_batch_idpulled_batch_idpushedpulled
sync changeset¶
decentdb sync changeset create --db=<path> --from-checkpoint=<peer:sequence> --output=<changeset.json> [--scope=<scope>] [--shape=<shape>] [--max-records=<n>] [--max-bytes=<n>]
decentdb sync changeset create --db=<path> --from-branch=<left> --to-branch=<right> --output=<changeset.json>
decentdb sync changeset create --db=<path> --from-snapshot=<snapshot> --to-branch=<branch> --output=<changeset.json>
decentdb sync changeset inspect --input=<changeset.json> [--db=<path>] [--check-local] [--format=<json|table>]
decentdb sync changeset apply --db=<path> --input=<changeset.json> [--conflict-policy=<record|stop|last-writer-wins|origin-priority>] [--format=<json|table>]
decentdb sync changeset invert --input=<changeset.json> --output=<inverse.json> [--db=<path>] [--format=<json|table>]
- Checkpoint changesets are created from the durable sync journal.
- Branch and snapshot changesets reuse branch diff semantics and reject unsupported row-diff cases before producing output.
inspect --check-localvalidates local schema/query compatibility without mutating data.applyis transactional by default and idempotent for already-applied changeset IDs with the same integrity hash.invertonly succeeds when enough before-state is available.
relay¶
decentdb relay serve --db=<path> --listen=<host:port> --auth-token-env=<ENV> [--public-url=<https-url>] [--require-tls] [--allow-insecure] [--ready-file=<path>] [--max-requests=<n>] [--json]
decentdb relay status --db=<path> [--format=<json|table>]
decentdb relay doctor --db=<path> [--format=<json|table>]
decentdb relay shape create --db=<path> --shape=<shape> --scope=<scope> --tenant=<tenant> [--allow-role=<role>] [--allow-subject=<subject>] [--format=<json|table>]
decentdb relay shape list --db=<path> [--format=<json|table>]
decentdb relay shape drop --db=<path> --shape=<shape> [--format=<json|table>]
decentdb relay shape status --db=<path> --shape=<shape> [--format=<json|table>]
decentdb relay shape snapshot --db=<path> --shape=<shape> --client-replica-id=<replica> --output=<changeset.json> [--format=<json|table>]
relay serve exposes production v2 routes under /decentdb/sync/v2:
GET /helloGET /statusGET /sessionsPOST /sessionsPOST /changesets/exportPOST /changesets/applyPOST /changesets/inspectPOST /changesets/invertGET /shapesPOST /shapes/{shape_id}/snapshotGET /shapes/{shape_id}/changes?since=<watermark>POST /acksGET /conflictsGET /diagnosticsGET /streamwith a WebSocket upgrade
Production requests require a bearer token unless --allow-insecure is set. Principal context is provided by x-decentdb-* headers. Browser WebSocket clients can use short-lived query parameters on /stream because the browser WebSocket API cannot set custom headers.
sync conflicts / conflict¶
decentdb sync conflicts --db=<path> [--all] [--format=<json|table>]
decentdb sync conflict show --db=<path> --id=<conflict-id> [--format=<json|table>]
decentdb sync conflict resolve --db=<path> --id=<conflict-id> --action=<keep-local|apply-remote> [--by=<user>] [--note=<text>] [--format=<json|table>]
decentdb sync conflict reopen --db=<path> --id=<conflict-id> [--format=<json|table>]
decentdb sync conflict policy get --db=<path> [--format=<json|table>]
decentdb sync conflict policy set --db=<path> --policy=<record|stop|last-writer-wins|origin-priority> [--origin-priority=<peer1,peer2,...>] [--format=<json|table>]
sync conflictslists unresolved conflicts by default.--allincludes resolved conflicts too.policy get/setoperate on the default conflict policy plus optional origin priority list.
Example:
decentdb sync conflicts --db=app.ddb --format=table
decentdb sync conflict show --db=app.ddb --id=1 --format=json
decentdb sync conflict resolve --db=app.ddb --id=1 --action=keep-local --by=ops --note="manual override"
decentdb sync conflict reopen --db=app.ddb --id=1
sync doctor / prune¶
decentdb sync doctor --db=<path> [--format=<json|table>]
decentdb sync prune --db=<path> --through=<sequence> [--dry-run] [--allow-data-loss] [--format=<json|table>]
sync doctoraggregates journal integrity, retention, peer lag, unresolved conflicts, recent sessions, and guidance strings.sync prune --dry-runreports what would be removed without rewriting the journal.--allow-data-losspermits pruning beyond the safe watermark.
Example:
decentdb sync doctor --db=app.ddb --format=table
decentdb sync prune --db=app.ddb --through=42 --dry-run --format=table
Output Formats¶
json renders machine-readable tables or command results.
csv renders comma-separated rows.
table renders an aligned plain-text table with headers.