CLI Reference
The db9 CLI is the primary interface for creating databases, running SQL, managing files, branching, and onboarding AI agents. This page is a complete command reference.
Common Journeys
Section titled “Common Journeys”| I want to… | Start here |
|---|---|
| Try DB9 in under two minutes | Quick Start |
| Connect an ORM or driver | Connect |
| Understand the architecture | Architecture |
| Set up DB9 for Claude Code or Codex | Agent Workflows |
| Create databases programmatically | Provisioning |
| Inspect query performance | Inspect & Observability below |
| Run SQL from the terminal | SQL Execution below |
| Upload files to a database | Filesystem below |
| Create a branch for testing | Branching below |
| Schedule recurring SQL jobs | Cron Jobs below |
| Watch filesystem changes in real time | Filesystem Watch below |
| Deploy serverless functions (experimental) | Functions below |
| Prepare for production | Production Checklist |
Installation
Section titled “Installation”Install with the official script (Linux/macOS, amd64/arm64):
curl -fsSL https://db9.ai/install | shTo control where binaries land, set DB9_INSTALL_DIR:
DB9_INSTALL_DIR="$HOME/.local/bin" curl -fsSL https://db9.ai/install | shVerify:
db9 --versiondb9 statusThe installer places db9 (and optionally db9-fuse for FUSE mounts) into your chosen directory.
macOS prerequisite for db9 fs mount
Section titled “macOS prerequisite for db9 fs mount”db9 fs mount on macOS currently depends on the macFUSE kernel backend.
brew install --cask macfuseAfter installation, macOS may require manual system extension approval in System Settings > Privacy & Security before FUSE mounts are allowed.
Global Flags
Section titled “Global Flags”These flags work with every db9 command. All of them can go before or after the subcommand except
--api-url, which must come before it: db9 --api-url <URL> list works, while
db9 list --api-url <URL> fails with error: unexpected argument '--api-url' found.
| Flag | Env Variable | Default | Description |
|---|---|---|---|
--api-url <URL> | DB9_API_URL | https://api.db9.ai | API base URL. api_url in ~/.db9/config.toml applies when neither the flag nor the variable is set, or when they are set to the default https://api.db9.ai |
--output <FORMAT> | — | table | Output format: table, json, csv, raw (tab-separated values, no header row, no quoting), or quiet (minimal machine-readable) |
--json | — | — | Shorthand for --output json |
--quiet | — | — | Suppress non-essential output (only print machine-readable values) |
--insecure | DB9_INSECURE | — | Skip TLS certificate verification |
--experimental | DB9_EXPERIMENTAL | — | Accepted but currently has no effect; functions and every other command work without it |
-v, --verbose | — | — | On exit, print an HTTP request summary (method, URL, status, time, bytes) to stderr |
-d, --database <DB> | DB9_DATABASE | — | Override the default database for this command |
Authentication
Section titled “Authentication”DB9 supports three auth paths: anonymous trial, SSO login, and API key (CI/agents). Tokens are stored in ~/.db9/credentials.
Security: Treat
DB9_API_KEYas a secret. Never send your token to any domain other thanapi.db9.ai.
# Zero-setup trial (auto creates anonymous account + token)db9 create --name quickstart
# Upgrade anonymous account to verified SSO identitydb9 claimdb9 claim --id-token <AUTH0_ID_TOKEN>
# Human operator login (browser-based)db9 login
# API key login (CI/CD, agents)db9 login --api-key <KEY>
# Agent runtimeexport DB9_API_KEY=<token>See Token Management for creating automation tokens.
Adopt Anonymous Databases
Section titled “Adopt Anonymous Databases”Transfer databases created under an anonymous trial account into your verified account:
db9 adoptThis launches an interactive flow that verifies ownership of the anonymous account (via anonymous_secret) and migrates selected databases into your current account. For details, see Anonymous & Claimed Databases.
Setup & Utilities
Section titled “Setup & Utilities”# Guided setup: login and create your first databasedb9 init
# Set or show default database (omit DB to show current)db9 use <db>db9 use --clear
# Remove stored credentials (-y/--yes skips the confirmation prompt;# --force logs out even if anonymous databases have not been adopted)db9 logout
# Update db9 (and db9-fuse) to the latest versiondb9 update
# Generate shell completion scriptsdb9 completion bashdb9 completion zsh
# Show / set CLI configurationdb9 config showdb9 config set api_url https://api.db9.aiDatabase Lifecycle
Section titled “Database Lifecycle”Database commands accept <db> as a database name (preferred) or ID. When omitted, the default database set by db9 use is used.
These are top-level commands — use db9 create, not db9 db create.
# Create (name is optional; will auto-generate if omitted)db9 create --name myappdb9 create --name myapp --region us-westdb9 create --name myapp --project <project_id> # assign to a projectdb9 create --name myapp --password <password> # set the admin password (default: random)db9 create --name myapp --show-password # also print the admin password (with --json: include admin_password)db9 create --name myapp --show-secrets # same as --show-password --show-connection-string
# Listdb9 list
# List with database storage sizesdb9 list --size
# Filter by projectdb9 list --project <project_id>
# Check login statusdb9 status
# Show database statusdb9 db status <db>
# Print a temporary DSN (psql-compatible); its password is a connect token valid for 10 minutesdb9 db connect <db>
# Output connection as DATABASE_URL=... format (for .env files)db9 db connect <db> --env
# Create a short-lived connect token (10-min TTL, for psql/ORM usage) — same as `db9 db connect`, use --user for a specific roledb9 db connect <db> --user app_user
# Reset admin passworddb9 db reset-password <db>
# Delete (prompts unless you pass --yes)db9 delete <db> --yesdb9 create always prints the connection string; --show-connection-string is accepted for backward
compatibility and changes nothing. In --json output, connection_string carries no password — the
password is in admin_password, which is present only with --show-password or --show-secrets.
Deprecated forms:
db9 db create,db9 db list,db9 db delete,db9 db branch, anddb9 db connect-tokenstill work but print a deprecation warning. Use the top-level forms instead (db9 db connect-token→db9 db connect). Note the deprecateddb9 db connect-tokentakes--role, whiledb9 db connecttakes--user; neither accepts the other’s flag.
db9 list output
Section titled “db9 list output”The table form prints a leading unlabeled column that marks the default database with *, followed by:
| Column | Shown by default | Notes |
|---|---|---|
ID | yes | 12-character database ID |
NAME | yes | |
STATE | yes | Uppercase, e.g. ACTIVE |
REGION | yes | |
PROJECT | yes | Project UUID |
CREATED | yes | |
LAST ACTIVE | yes | - until activity is observed |
SIZE | only with --size | Requires an extra API call per database |
LAST MODIFIED | only with --size |
db9 list --json returns an array of objects with nine fields: id, name, state, region,
project_id, created_at, last_active_at, last_modified_at, and default. The two activity
fields are RFC 3339 timestamps, or null when no activity has been observed yet; db9 db status --json carries them too.
For programmatic database creation patterns, see Provisioning.
Shorthand Aliases
Section titled “Shorthand Aliases”Most db9 db <cmd> subcommands have top-level aliases so you can type less:
| Shorthand | Equivalent |
|---|---|
db9 sql <db> | db9 db sql <db> |
db9 connect <db> | db9 db connect <db> |
db9 inspect <db> | db9 db inspect <db> |
db9 users <db> | db9 db users <db> |
db9 seed <db> | db9 db seed <db> |
db9 dump <db> | db9 db dump <db> |
db9 cron <db> | db9 db cron <db> |
db9 cat <db>:/path | Read a remote file |
db9 rm <db>:/path | Remove a remote file |
db9 mv <db>:/src <db>:/dst | Move/rename a remote file |
db9 sh <db> | db9 fs sh <db> |
db9 cp <src> <dst> | db9 fs cp <src> <dst> |
db9 ls <db>:/path | db9 fs ls <db>:/path |
db9 mount <db> <dir> | db9 fs mount <db> <dir> |
The cat, rm, and mv shorthands operate on the database filesystem directly — no need for db9 fs sh.
Inspect and Observability
Section titled “Inspect and Observability”| Subcommand | Description |
|---|---|
db9 db inspect | Overview metrics dashboard |
db9 db inspect queries | Query samples and performance |
db9 db inspect report | Combined summary + queries report |
db9 db inspect schemas | List database schemas |
db9 db inspect tables | List database tables |
db9 db inspect indexes | List database indexes |
db9 db inspect slow-queries | Slow queries sorted by p99 latency |
# Overview metricsdb9 db inspect <db>
# Subcommandsdb9 db inspect <db> queries # query samples and performancedb9 db inspect <db> report # combined summary + queries reportdb9 db inspect <db> schemas # list database schemasdb9 db inspect <db> tables # list database tablesdb9 db inspect <db> indexes # list database indexesdb9 db inspect <db> slow-queries # slow queries sorted by p99 latencyFor production monitoring guidance, see Production Checklist.
Database Users
Section titled “Database Users”# List database usersdb9 db users <db> list
# Create a new database user (--password is required; omitting it fails with# "Error 400: password is required")db9 db users <db> create --username app_user --password 'SecurePass1'
# Delete a database userdb9 db users <db> delete --username app_userSQL Execution
Section titled “SQL Execution”Run SQL via inline query (-q / --query), file (-f / --file), stdin, or an interactive REPL. The <db> argument is optional — if omitted, the CLI auto-selects the default database or prompts interactively.
The interactive REPL defaults to direct pgwire mode (faster, real PostgreSQL error messages) with automatic API fallback. Use --api to force HTTP API mode, or --direct / -D to explicitly request pgwire.
# Inlinedb9 db sql <db> --query "SELECT now()"
# From filedb9 db sql <db> --file ./query.sql
# From stdincat ./query.sql | db9 db sql <db>
# Interactive REPL (TTY only — defaults to direct pgwire)db9 db sql <db>
# Force HTTP API mode (disables auto-direct in REPL)db9 db sql <db> --api
# Explicit direct pgwire modedb9 db sql <db> --directdb9 db sql <db> --direct --dsn "postgresql://..."
# Execute a seed SQL filedb9 db seed <db> ./seed.sql
# Export database schema (and optionally data) as SQLdb9 db dump <db>db9 db dump <db> --ddl-onlydb9 db dump <db> --output-file ./backup.sqlThe REPL accepts psql-style backslash commands; \? lists them. To inspect the schema, use
\d [TABLE], \dt, \dv, \dn, \di, and \du, and (since CLI 2.2.5) \d+ [TABLE], which adds
storage and comments, and \dt+ [TABLE], which adds owner, persistence, and comments. They print
DB9’s own tables, not psql’s layout: \d+ TABLE prints one row per column and no index list, and
\dt+ shows NULL for access method and size.
Filesystem
Section titled “Filesystem”Each database has a remote filesystem. Use db9 fs for shell access, file copy, and (optionally) FUSE mounts.
# List remote files and directoriesdb9 fs ls <db>:/pathdb9 fs ls --long <db>:/path # long format (permissions, size, mtime)db9 fs ls --recursive <db>:/path # recursive listing
# Interactive filesystem shelldb9 fs sh <db>
# Run a single command (bash -c style)db9 fs sh <db> --command "ls -la"
# Quick file operations (top-level shortcuts)db9 cat <db>:/path/to/file # Print file contentsdb9 rm <db>:/path/to/file # Remove a filedb9 mv <db>:/old/path <db>:/new/path # Move or renamedb9 tailf <db>:/logs/app.log # Follow remote file appends
# Upload / download (scp-like)db9 fs cp ./local.txt <db>:/remote/path/local.txtdb9 fs cp <db>:/remote/path/remote.txt ./remote.txt
# Recursive upload / download (directories)db9 fs cp --recursive ./imports <db>:/data/imports
# Glob upload / multi-file upload (the destination directory must already exist)db9 fs cp ./*.go <db>:/remote/db9 fs cp a.go b.go <db>:/remote/
# Mount via FUSE (requires db9-fuse and system FUSE support)db9 fs mount <db> "$HOME/mnt/mydb"db9 fs mount <db> "$HOME/mnt/mydb" --read-onlydb9 fs mount <db> "$HOME/mnt/mydb" --cache-ttl 30db9 fs mount <db> "$HOME/mnt/mydb" --multipart-threshold 16777216 # 16 MBdb9 fs mount <db> "$HOME/mnt/mydb" -f # foregrounddb9 fs mount <db> "$HOME/mnt/mydb" --write-async # client async writeback (alias: --writeback); close() seals to local journal, drains opportunistically — not a remote-commit promisedb9 fs mount <db> "$HOME/mnt/mydb" --include '*.md' # sync only .md filesdb9 fs mount <db> "$HOME/mnt/mydb" --include '*.rs' --exclude 'target/**'db9 fs mount <db> "$HOME/mnt/mydb" --no-ignore # disable .fuseignoreA single-file copy to a full destination path and a --recursive copy create missing remote parent
directories. A multi-file or glob copy does not: if the destination directory is missing it fails
with cp: /remote: ENOENT: not found. Create the directory first, for example with
db9 fs sh <db> --command "mkdir -p /remote".
FUSE cache tuning: --attr-cache-size <N>, --dir-cache-size <N>, and --dir-entry-limit <N>
override the attribute cache capacity, the directory cache capacity, and the directory entry
promotion limit (the defaults are internal constants).
Filesystem Watch
Section titled “Filesystem Watch”Monitor filesystem events in real time. The watch command uses WebSocket push when the server advertises the watch capability, and falls back to polling the fs9_events() table function when it does not.
# Watch all events on a databasedb9 fs watch <db>:/
# Watch events under a specific pathdb9 fs watch <db>:/data/
# Poll every 5 seconds (default: 1) — applies only to the polling fallbackdb9 fs watch <db>:/ --interval 5
# Output JSON lines (for piping to other tools)db9 fs watch <db>:/ --jsonWith WebSocket push, each event is one line with a lowercase event type — created, modified,
deleted, renamed, mkdir, or other — followed by the path and a sequence number. Events carry no
timestamp or file size, and a rename reports only the new path:
[created] /data/file.txt seq=1790005218589000000[modified] /data/file.txt seq=1790005220169000000[renamed] /data/new.txt seq=1790005221923000000[mkdir] /data/reports seq=1790005226028000000[deleted] /data/new.txt seq=1790005227835000000With --json, each line is an object with the same three values:
{"event_type":"modified","path":"/data/file.txt","stream_id":"1790005220169000000"}Push watch does not need the fs9 extension. The polling fallback does, and prints a different, timestamped line format.
Once the subscription is live, the CLI prints a one-line readiness object to stderr (not stdout,
which stays an event-only stream — so it does not disturb --json consumers):
{"elapsed_ms":299,"transport":"push-subscription","type":"fs_watch_ready"}transport is push-subscription for WebSocket push or sql-polling when the command has fallen
back to polling fs9_events(), which makes it the quickest way to tell which path you got.
Redirect stderr (2>/dev/null) if you only want events.
If the server reports that events were dropped, the CLI prints warning: event gap (last_known_seq: …)
to stderr. Rescan the paths you care about when you see it.
File Tail (follow)
Section titled “File Tail (follow)”Follow a remote file and print appended content, similar to tail -f:
# Follow a log file (prints last 10 lines, then streams new content)db9 fs tailf <db>:/logs/app.log
# Show last 50 lines before followingdb9 fs tailf <db>:/logs/app.log --lines 50
# Custom polling interval (default: 1 second)db9 fs tailf <db>:/logs/app.log --interval 2tailf follows the file by polling fs9_events(), so following requires the
fs9 extension. Without it, the command prints the last lines and then exits
with error: The fs9 extension is not enabled on this database. Run CREATE EXTENSION fs9 on the
database first.
Tee (stdin to remote file)
Section titled “Tee (stdin to remote file)”Read stdin, echo it to stdout, and write it to a remote file — like Unix tee but targeting the database filesystem:
# Pipe command output to a remote fileecho "hello" | db9 fs tee <db>:/logs/out.txt
# Append instead of overwritingcat local.txt | db9 fs tee -a <db>:/logs/out.txt| Flag | Default | Description |
|---|---|---|
-a, --append | off | Append to the file instead of overwriting |
The parent directory must already exist. Otherwise tee still echoes stdin, then fails with
tee: /logs/out.txt: /logs/out.txt: not found.
Advanced filesystem flags (all fs subcommands): --ws-url <URL> (direct WebSocket URL), --ws-port <PORT> (default: 5480).
Filesystem Shell Builtins
Section titled “Filesystem Shell Builtins”The interactive shell (db9 fs sh) supports a POSIX-like command set:
| Category | Commands |
|---|---|
| File ops | ls, cat, cp, mv, rm, touch, mkdir, stat, find, tree, diff, patch |
| Text processing | grep, head, tail, sort, uniq, cut, wc, tr, rev, tee, jq |
| Navigation | cd, pwd, basename, dirname |
| Shell | echo, printf, read, export, set, test, alias, source, env, date, sleep, seq |
| Control flow | if/then/fi, for/do/done, while/do/done, case/esac, pipes, redirections |
Use help <command> inside the shell for per-command usage.
For querying files with SQL, see fs9 extension.
Migrations
Section titled “Migrations”Manage local migration files and apply them to a database. Default directory is ./migrations.
# Create a new migration filedb9 migration new create_users
# List local migration filesdb9 migration list
# See applied vs pendingdb9 migration status <db>
# Apply pending migrationsdb9 migration up <db>All migration subcommands accept --dir <path> to override the default ./migrations directory.
Branching
Section titled “Branching”Branches are full copies of a database — schema, data and fs9 files, but not functions or their secrets — used for safe experimentation. Branch commands are top-level under db9 branch.
# Create a branch from an existing databasedb9 branch create <db> --name feature1db9 branch create <db> --name feature1 --show-secrets # print password + connection stringdb9 branch create <db> --name feature1 --show-password # print password onlydb9 branch create <db> --name feature1 --show-connection-string # print connection string only
# Point-in-time branch (PITR) — branch from a specific past timestampdb9 branch create <db> --name rollback --snapshot-at 2026-03-22T06:00:00Z
# List branches of a databasedb9 branch list <db>
# Delete a branch database (prompts unless you pass -y/--yes)db9 branch delete <branch_db>db9 branch delete <branch_db> --yesThe --snapshot-at flag accepts an RFC 3339 UTC timestamp (e.g. 2026-03-22T06:00:00Z). When TiKV snapshot restore is available, the branch will contain the parent’s data as of that timestamp rather than the current state.
For branch-based workflows (preview environments, rollback, task isolation), see Multi-Tenant Patterns.
Cron Jobs
Section titled “Cron Jobs”Schedule SQL with pg_cron (extension required). Cron commands live under db9 db cron.
| Subcommand | Description |
|---|---|
db9 db cron list | List all cron jobs |
db9 db cron create | Create a cron job |
db9 db cron delete | Delete a job by ID or name |
db9 db cron history | Show job execution history |
db9 db cron enable | Enable a disabled job |
db9 db cron disable | Disable a job |
db9 db cron status | Show job status |
# List jobsdb9 db cron <db> list
# Create (schedule + SQL command)db9 db cron <db> create "*/5 * * * *" "SELECT 1"
# Create from file (optional name enables upsert semantics)db9 db cron <db> create "0 * * * *" --name hourly_job -f ./job.sql
# History / statusdb9 db cron <db> history --job <job_id_or_name> --limit 20db9 db cron <db> status
# Enable / disable / delete by job id or job namedb9 db cron <db> disable <job>db9 db cron <db> enable <job>db9 db cron <db> delete <job>For scheduling patterns and operational guidance, see pg_cron extension.
Functions
Section titled “Functions”Serverless functions let you deploy and run JavaScript/TypeScript code that executes against your database.
| Subcommand | Description |
|---|---|
db9 functions list | List functions in a database |
db9 functions create | Create a new function |
db9 functions update | Update an existing function by name or ID |
db9 functions invoke | Invoke a function |
db9 functions history | List recent runs, or show details of a specific run |
db9 functions logs | Show logs for a specific run |
db9 functions secrets list | List all secrets (names only) |
db9 functions secrets set | Create or update a secret |
db9 functions secrets delete | Delete a secret |
# List functions (this subcommand takes --database or a positional DB, not --db)db9 functions list --database myapp
# Create a function (reads index.js or main.ts from current directory)db9 functions create my-func --db myapp
# Create with TypeScript sourcedb9 functions create my-func --db myapp --ts
# Create with execution limitsdb9 functions create my-func --db myapp \ --limits-json '{"timeout_ms":60000,"memory_mb":128}'db9 functions create my-func --db myapp --limits-file ./limits.jsondb9 functions create my-func --db myapp --timeout 30000
# Bind secrets to a functiondb9 functions create my-func --db myapp --secret API_KEY=my_api_key
# Grant filesystem access to a functiondb9 functions create my-func --db myapp --fs9-scope /data:ro --fs9-scope /output:rw
# Create a public function (callable via publishable key)db9 functions create my-func --db myapp --visibility public
# Return node-postgres compatible results from ctx.db.query (default: sql-api)db9 functions create my-func --db myapp -f index.js --db-api pg
# Update an existing function (every update uploads source and creates a new version)db9 functions update my-func --db myapp -f ./updated.jsdb9 functions update my-func --db myapp -f ./index.js --timeout 60000 --secret NEW_KEY=my_new_keydb9 functions update my-func --db myapp -f ./index.js --visibility privatedb9 functions update my-func --db myapp -f ./index.js \ --limits-json '{"timeout_ms":60000,"memory_mb":128}'
# Switch the result format back (an update without --db-api keeps the current one)db9 functions update my-func --db myapp -f ./index.js --db-api sql-api
# Invoke a functiondb9 functions invoke my-func --db myappdb9 functions invoke my-func --db myapp --payload '{"key":"value"}'
# View run history and logsdb9 functions history my-func --db myapp -n 50db9 functions history my-func <run_id> --db myappdb9 functions logs my-func <run_id> --db myapp
# Manage secretsdb9 functions secrets list --db myappdb9 functions secrets set MY_SECRET --db myapp --value "secret-value"db9 functions secrets set MY_SECRET --db myapp --value-stdindb9 functions secrets delete MY_SECRET --db myappThe --db flag is optional when a default database is set via db9 use. The --timeout convenience flag overrides any timeout_ms value in the limits JSON.
--db-api (CLI 2.2.5) chooses what ctx.db.query returns: sql-api (the default) or pg, which
gives node-postgres results and errors — see
Runtime & ctx. Any other value is a usage error.
db9 functions invoke exits 0 even when the run fails or times out: it prints
Run <run_id>: failed (or timed_out) and the error message. In scripts, check status in the
--json output.
functions update has no settings-only mode: it always uploads source, and accepts the same
--limits-json, --limits-file, --ts, and --db-api flags as create. It reads the source from -f <path>
(-f - for stdin). Without -f, it reads index.js, index.ts, main.js, or main.ts from the
current directory when stdin is a terminal, and stdin otherwise. In scripts and CI, an update without -f
fails with Empty source. Provide function code via --file, stdin, or index.js. when stdin is empty,
or waits indefinitely when stdin stays open. To change only --timeout, --secret, --visibility,
--db-api, or limits, pass the function’s current source with -f.
Sharing
Section titled “Sharing”db9 share is a shorthand for creating a database-scoped token. It creates the token and prints a ready-to-use connection string.
# Read-only share (default), 7-day expirydb9 share my-app
# Read-write sharedb9 share my-app --rw
# Custom expiry (30 days)db9 share my-app --expires 30
# Custom token namedb9 share my-app --name team-token| Flag | Default | Description |
|---|---|---|
--rw | off | Grant read-write access (default: read-only) |
--expires <days> | 7 | Token expiry in days |
--name <name> | share-<db>-YYYYMMDD | Custom token name |
Under the hood this calls POST /customer/tokens with the appropriate scope_json. For more control (multi-database scopes, custom names), use db9 token create --scope.
Explorer
Section titled “Explorer”db9 explore launches a browser-based file and SQL explorer. It downloads a pre-built SPA to ~/.db9/explorer/ and serves it locally with API proxying.
# Open explorer for a databasedb9 explore mydb
# Custom portdb9 explore mydb --port 8080
# Don't auto-open the browserdb9 explore mydb --no-open
# Use cached assets without checking for updatesdb9 explore --no-download
# Force re-download even if cacheddb9 explore mydb --force-download| Flag | Default | Description |
|---|---|---|
--port <port> | 7979 | Local port (env: DB9_EXPLORER_PORT) |
--no-open | off | Skip automatic browser open |
--no-download | off | Use cached assets, skip update check |
--force-download | off | Re-download assets even if cached |
Token Management
Section titled “Token Management”Create and manage API tokens for CI/CD pipelines, automation, and agent workflows.
# Show the current raw token (for use with DB9_API_KEY)db9 token show
# Create a new API token (default: 365-day expiry)db9 token create --name my-agentdb9 token create --name ci-token --expires-in-days 90
# Create a database-scoped token (read-only or read-write)db9 token create --name readonly-token --scope mydb:rodb9 token create --name multi-db --scope app:rw --scope analytics:ro
# List your API tokens (--all also shows auto-created tokens such as SSO session tokens)db9 token listdb9 token list --all
# Revoke a token (prompts unless you pass -y/--yes)db9 token revoke <token_id>db9 token revoke <token_id> --yesStore created tokens in a secret manager. See Production Checklist for token security guidance.
Type Generation
Section titled “Type Generation”Generate types from the live schema (prints to stdout). Available languages: TypeScript and Python.
# TypeScriptdb9 gen types <db> --lang typescript --schema public > db9.types.ts
# Pythondb9 gen types <db> --lang python --schema public > db9_types.pyAgent Onboarding
Section titled “Agent Onboarding”db9 onboard installs or updates the DB9 skill into supported local coding agents. It does not require login and does not send tokens anywhere.
# Interactive wizarddb9 onboard
# Non-interactivedb9 onboard --yes --alldb9 onboard --yes --agent codex --agent claude --scope user
# Safety / introspection (zero filesystem changes)db9 onboard --dry-rundb9 onboard --print-locations
# Advanced: custom skill sourcedb9 onboard --skill-url https://db9.ai/skill.mddb9 onboard --skill-path ./SKILL.mddb9 onboard --forceSupported agents and default install locations:
| Agent | --scope user | --scope project | Notes |
|---|---|---|---|
codex | ~/.codex/skills/db9/SKILL.md (or $CODEX_HOME/…) | — | Codex currently supports user scope only |
claude | ~/.claude/skills/db9/SKILL.md | ./.claude/skills/db9/SKILL.md | --scope both installs both |
opencode | ~/.config/opencode/skills/db9/SKILL.md | ./.opencode/skills/db9/SKILL.md | --scope both installs both |
agents | ~/.agents/skills/db9/SKILL.md | ./.agents/skills/db9/SKILL.md | Generic agent-compatible directory |
For agent workflow patterns, see Agent Workflows.
Error Messages
Section titled “Error Messages”Common errors and how to resolve them. Messages are printed to stderr; … marks a variable part.
| Message | Cause | Resolution |
|---|---|---|
Not logged in. Run 'db9 login' first, or set DB9_API_KEY. | No stored credentials and no DB9_API_KEY. Most commands create an anonymous account in this case instead; db9 status and db9 functions do not | Run db9 login or set DB9_API_KEY |
Session expired. Run 'db9 login' to re-authenticate. | The API rejected the token: it expired, was revoked, or DB9_API_KEY is invalid. db9 status reports this as error: DB9_API_KEY is set but invalid. … or error: Token expired or invalid. … | Run db9 login, or set a valid DB9_API_KEY (db9 token create) |
Database '<name>' not found. Use 'db9 list' to view available targets. (db9 fs commands print Error: Database not found) | Wrong name/ID, or the database was deleted | Run db9 list to see available databases |
Error 403: Read-only token cannot perform write operations or Error 403: Scoped tokens cannot perform this operation | The token’s --scope does not allow the operation | Use a token with the needed scope, or an unscoped token (db9 token create) |
Connection failed: error sending request for url (…) | API endpoint unreachable | Check network; verify the --api-url flag or DB9_API_URL env var |
Error 429: … | Too many requests; the message depends on the endpoint | Wait and retry; implement exponential backoff in scripts |
Error 409: Database name already exists for this account | Duplicate database name | Choose a different name, or delete the existing database first |
Error 403: Database limit reached (max 5). Run 'db9 claim' to upgrade your account. | Anonymous account already has 5 databases (branches count) | Delete a database or run db9 claim |
Error 409: Database is not active. Retry when state is ACTIVE. (db9 fs commands print Error: Database is not active. …) | Database is in CREATING, CLONING, or DISABLED state | Check state with db9 db status <name>; wait for ACTIVE |
No databases found. Create one with 'db9 create --name <name>'. | No database argument, no default, and the account has no databases | Run db9 create --name <name> to create one |
Failed to build fs transport: … (with --ws-url: Failed to connect or authenticate: …) | A db9 fs command could not open the filesystem connection | Verify the database is active; check fs_websocket_url with db9 db status <name> --json |
Exit Codes
Section titled “Exit Codes”db9 follows standard Unix exit code conventions for use in shell scripts and CI/CD pipelines.
| Code | Meaning | Example trigger |
|---|---|---|
0 | Success | Command completed without errors (including --help and --version) |
1 | Runtime error | The command parsed, but failed — database not found, SQL error, API error. See stderr |
2 | Usage error | The command did not parse — unknown subcommand or flag, missing required argument, invalid flag value |
Check for any non-zero code rather than testing for 1 specifically: a typo in a flag
name exits 2, not 1. A function run that fails is not a command failure:
db9 functions invoke still exits 0 (see Functions).
Usage in shell scripts:
db9 create --name mydbif [ $? -ne 0 ]; then echo "Database creation failed" >&2 exit 1fi
# Or inlinedb9 create --name mydb || { echo "Failed"; exit 1; }Capturing error output:
output=$(db9 db sql mydb -q "SELECT 1" 2>&1)if [ $? -ne 0 ]; then echo "Error: $output" >&2 exit 1fiTroubleshooting
Section titled “Troubleshooting”Authentication failures
Section titled “Authentication failures”Symptom: Not logged in. … or Session expired. … errors.
# Check current auth statusdb9 status
# Re-authenticate interactivelydb9 login
# Use an API key directly (CI/CD)export DB9_API_KEY=your-tokendb9 list
# View the credentials filecat ~/.db9/credentials
# List all tokensdb9 token listNetwork errors
Section titled “Network errors”Symptom: Connection failed: error sending request for url (…) or timeouts when running any command.
# Show the API URL each request actually went to (summary on stderr)db9 -v list
# Show the api_url saved in ~/.db9/config.toml (a non-default --api-url or DB9_API_URL overrides it)db9 config show
# Override the API URL for a single commanddb9 --api-url https://db9.internal.example.com list
# Set for the shell session via environmentexport DB9_API_URL=https://db9.internal.example.comIf behind a corporate proxy, ensure HTTPS_PROXY or https_proxy is set in your environment before running db9 commands.
Permission denied
Section titled “Permission denied”Symptom: Commands fail with Error 403: Read-only token cannot perform write operations or
Error 403: Scoped tokens cannot perform this operation after authentication succeeds.
API tokens can be created with limited scopes. Create a new full-access token and switch to it:
db9 token create --name full-accessexport DB9_API_KEY=<new-token>Database stuck in non-ACTIVE state
Section titled “Database stuck in non-ACTIVE state”Symptom: Error 409: Database is not active. Retry when state is ACTIVE. when running SQL, or
Error: Database is not active. … from db9 fs commands.
# Check current statedb9 db status mydbStates and meanings:
| State | Description |
|---|---|
CREATING | Initial provisioning in progress (usually < 30s) |
CLONING | Branch copy in progress |
ACTIVE | Ready for connections |
DISABLING | Deletion in progress |
DISABLED | Deleted or suspended |
CREATE_FAILED | Provisioning failed — delete and recreate |
For branch databases, poll until active:
while [ "$(db9 db status mydb --json 2>/dev/null | jq -r .state)" != "ACTIVE" ]; do echo "Waiting for ACTIVE state…" sleep 2doneFilesystem (fs9) connection errors
Section titled “Filesystem (fs9) connection errors”Symptom: Failed to build fs transport: … (or, with --ws-url, Failed to connect or authenticate: …) when using db9 fs commands.
# Verify the database is ACTIVEdb9 db status mydb
# Check the WebSocket URL is presentdb9 db status mydb --json | jq .fs_websocket_urlIf using the TypeScript SDK on Node.js 18–20, install the ws package:
npm install wsThen pass it as the WebSocket option when creating the client — see Filesystem (client.fs).
Verbose debug output
Section titled “Verbose debug output”Add -v (--verbose) to any command to print an HTTP request summary — method, URL, status,
time, and bytes for each request — to stderr on exit. For detailed client logs, set RUST_LOG
(default level: warn); logs also go to stderr.
db9 -v listdb9 -v db sql mydb -q "SELECT 1"RUST_LOG=debug db9 listNext Steps
Section titled “Next Steps”- TypeScript SDK — Server-side database management with get-db9
- Browser SDK — Client-side data access with @db9/browser
- SQL Reference — SQL engine compatibility and features
- Extensions — fs9, HTTP, vector, pg_cron, and more
- Connect — Connection strings, TLS, and driver configuration