Skip to content

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

decentdb version

exec

Execute one or more SQL statements.

decentdb exec --db=<path> --sql="<sql>" [options]

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.

decentdb serve --db=<path> [options]
decentdb serve <path> [options]

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.

decentdb import --db=<path> --table=<name> --input=<file.csv> [--batchSize=<n>]

Current Rust CLI scope: CSV import only.

export

Export a table as CSV or JSON.

decentdb export --db=<path> --table=<name> --output=<path> [--format=<csv|json>]

bulk-load

Bulk load CSV data with explicit bulk-load options.

decentdb bulk-load --db=<path> --table=<name> --input=<file.csv> [options]

Supported options: - --batchSize=<n> - --syncInterval=<n> - --disableIndexes - --noCheckpoint

checkpoint

decentdb checkpoint --db=<path>

save-as

Write a checkpointed snapshot into a new on-disk database file.

decentdb save-as --db=<path> --output=<dest>

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.

decentdb migrate --db=<path>

info

Show storage-level information.

decentdb info --db=<path> [--schema-summary] [--format=<json|csv|table>]

describe

Describe one table, including column flags and foreign key references.

decentdb describe --db=<path> --table=<name> [--format=<json|csv|table>]

list-tables

decentdb list-tables --db=<path> [--format=<json|csv|table>]

list-indexes

decentdb list-indexes --db=<path> [--table=<name>] [--format=<json|csv|table>]

list-views

decentdb list-views --db=<path> [--format=<json|csv|table>]

dump

Dump the current catalog and table contents as deterministic SQL.

decentdb dump --db=<path> [--output=<path>]

dump-header

Decode and print the fixed page-1 header.

decentdb dump-header --db=<path> [--format=<json|csv|table>]

rebuild-index

decentdb rebuild-index --db=<path> --index=<name>

rebuild-indexes

decentdb rebuild-indexes --db=<path> [--table=<name>]

completion

Emit a small static shell completion script.

decentdb completion [--shell=<bash|zsh>]

stats

Show page and cache sizing information.

decentdb stats --db=<path> [--format=<json|csv|table>]

vacuum

Checkpoint and rewrite the database into a new output file.

decentdb vacuum --db=<path> --output=<path> [--overwrite]

verify-header

Open the database, validate the fixed header, and print the decoded fields.

decentdb verify-header --db=<path> [--format=<json|csv|table>]

verify-index

Rebuild a named index logically and compare entry counts against the current runtime copy.

decentdb verify-index --db=<path> --index=<name> [--format=<json|csv|table>]

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.

decentdb doctor --db=<path> [options]

Supported options:

  • --format=<json|markdown> output format, default markdown
  • --checks=<all|header,storage,wal,fragmentation,schema,statistics,indexes,compatibility> limit checks to selected categories, default all
  • --verify-index=<name> repeatable, run expensive logical verification for named indexes
  • --verify-indexes run expensive logical verification for all indexes up to --max-index-verify

  • --max-index-verify=<n> safety cap for --verify-indexes, default 32

  • --fail-on=<info|warning|error> minimum severity that makes the process exit non-zero, default error
  • --include-recommendations[=true|false] include safe recommendation text and commands, default true
  • --path-mode=<absolute|basename|redacted> controls path rendering in output, default absolute
  • --fix apply 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:

decentdb doctor --db=my.ddb

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:

decentdb doctor --db=my.ddb --format=json --fail-on=warning

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:

decentdb doctor --db=my.ddb --verify-index=users_name_idx --verify-index=items_sku_idx

Expensive verification is always opt-in. Default runs do not verify any indexes.

Fix mode example:

decentdb doctor --db=my.ddb --fix

When --fix is present, doctor:

  1. Collects diagnostic findings.
  2. Plans eligible fixes from the v1 fix action catalog.
  3. Applies fixes in deterministic order.
  4. Re-collects facts and re-runs checks.
  5. Reports mode="fix", pre_fix_findings, findings, and fixes.

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.

decentdb tracing --db=<path> --view=<view> [--format=<json|table|markdown>] [--reset]

Supported views:

  • sessions — active session state
  • slow_queries — captured slow query events
  • lock_waits — captured lock-wait events
  • index_usage — per-index read/write counters
  • doctor_findings — merged static and runtime advisor findings
  • fix_plan — safe-to-apply fix plans

Supported options:

  • --format=<json|table|markdown> output format, default json
  • --reset clear 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 — display sys.plan_cache_summary (one row, aggregate counters and the configured memory budget)
  • list — display sys.plan_cache (one row per cached entry)
  • reset — execute PRAGMA flush_plan_cache on 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.unreadable
  • database.open_failed
  • compatibility.format_version_unknown
  • wal.many_versions
  • wal.long_readers_present
  • wal.reader_warnings_recorded
  • wal.shared_enabled
  • fragmentation.high
  • fragmentation.moderate
  • schema.no_user_tables
  • schema.many_indexes_on_table
  • index.verify_error
  • index.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 --fix is 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 init initializes 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 disable toggle capture without changing the replica ID.
  • sync status prints enabled, replica_id, next_sequence, journal_path, and journal_size_bytes.
  • sync pending shows 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 export writes a JSON SyncChangeBatch file.
  • sync import reads that batch file and applies it locally.
  • sync export currently 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:

seen=1, applied=1, skipped=0, conflicted=0

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>]
  • endpoint must start with http:// or https://.
  • token-env stores 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>]
  • include is a comma-separated list of table names.
  • row-filter is validated at create time.
  • sync scope unbind removes 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 run uses the registered peer endpoint and the peer-to-scope binding.
  • sync serve is a dev/test HTTP endpoint. It is not a hardened public server.
  • direction defaults to both.
  • limit controls batch size per phase.
  • retries applies 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_name
  • direction
  • remote_replica_id
  • retry_count
  • pushed_batch_id
  • pulled_batch_id
  • pushed
  • pulled

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-local validates local schema/query compatibility without mutating data.
  • apply is transactional by default and idempotent for already-applied changeset IDs with the same integrity hash.
  • invert only 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 /hello
  • GET /status
  • GET /sessions
  • POST /sessions
  • POST /changesets/export
  • POST /changesets/apply
  • POST /changesets/inspect
  • POST /changesets/invert
  • GET /shapes
  • POST /shapes/{shape_id}/snapshot
  • GET /shapes/{shape_id}/changes?since=<watermark>
  • POST /acks
  • GET /conflicts
  • GET /diagnostics
  • GET /stream with 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 conflicts lists unresolved conflicts by default.
  • --all includes resolved conflicts too.
  • policy get / set operate 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 doctor aggregates journal integrity, retention, peer lag, unresolved conflicts, recent sessions, and guidance strings.
  • sync prune --dry-run reports what would be removed without rewriting the journal.
  • --allow-data-loss permits 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.