Skip to content
Discord Get Started

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.

I want to…Start here
Try DB9 in under two minutesQuick Start
Connect an ORM or driverConnect
Understand the architectureArchitecture
Set up DB9 for Claude Code or CodexAgent Workflows
Create databases programmaticallyProvisioning
Inspect query performanceInspect & Observability below
Run SQL from the terminalSQL Execution below
Upload files to a databaseFilesystem below
Create a branch for testingBranching below
Schedule recurring SQL jobsCron Jobs below
Watch filesystem changes in real timeFilesystem Watch below
Deploy serverless functions (experimental)Functions below
Prepare for productionProduction Checklist

Install with the official script (Linux/macOS, amd64/arm64):

Terminal
curl -fsSL https://db9.ai/install | sh

To control where binaries land, set DB9_INSTALL_DIR:

Terminal
DB9_INSTALL_DIR="$HOME/.local/bin" curl -fsSL https://db9.ai/install | sh

Verify:

Terminal
db9 --version
db9 status

The installer places db9 (and optionally db9-fuse for FUSE mounts) into your chosen directory.

db9 fs mount on macOS currently depends on the macFUSE kernel backend.

Terminal
brew install --cask macfuse

After installation, macOS may require manual system extension approval in System Settings > Privacy & Security before FUSE mounts are allowed.

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.

FlagEnv VariableDefaultDescription
--api-url <URL>DB9_API_URLhttps://api.db9.aiAPI 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>—tableOutput 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)
--insecureDB9_INSECURE—Skip TLS certificate verification
--experimentalDB9_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

DB9 supports three auth paths: anonymous trial, SSO login, and API key (CI/agents). Tokens are stored in ~/.db9/credentials.

Security: Treat DB9_API_KEY as a secret. Never send your token to any domain other than api.db9.ai.

Terminal
# Zero-setup trial (auto creates anonymous account + token)
db9 create --name quickstart
# Upgrade anonymous account to verified SSO identity
db9 claim
db9 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 runtime
export DB9_API_KEY=<token>

See Token Management for creating automation tokens.

Transfer databases created under an anonymous trial account into your verified account:

Terminal
db9 adopt

This 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.

Terminal
# Guided setup: login and create your first database
db9 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 version
db9 update
# Generate shell completion scripts
db9 completion bash
db9 completion zsh
# Show / set CLI configuration
db9 config show
db9 config set api_url https://api.db9.ai

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.

Terminal
# Create (name is optional; will auto-generate if omitted)
db9 create --name myapp
db9 create --name myapp --region us-west
db9 create --name myapp --project <project_id> # assign to a project
db9 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
# List
db9 list
# List with database storage sizes
db9 list --size
# Filter by project
db9 list --project <project_id>
# Check login status
db9 status
# Show database status
db9 db status <db>
# Print a temporary DSN (psql-compatible); its password is a connect token valid for 10 minutes
db9 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 role
db9 db connect <db> --user app_user
# Reset admin password
db9 db reset-password <db>
# Delete (prompts unless you pass --yes)
db9 delete <db> --yes

db9 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, and db9 db connect-token still work but print a deprecation warning. Use the top-level forms instead (db9 db connect-token → db9 db connect). Note the deprecated db9 db connect-token takes --role, while db9 db connect takes --user; neither accepts the other’s flag.

The table form prints a leading unlabeled column that marks the default database with *, followed by:

ColumnShown by defaultNotes
IDyes12-character database ID
NAMEyes
STATEyesUppercase, e.g. ACTIVE
REGIONyes
PROJECTyesProject UUID
CREATEDyes
LAST ACTIVEyes- until activity is observed
SIZEonly with --sizeRequires an extra API call per database
LAST MODIFIEDonly 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.

Most db9 db <cmd> subcommands have top-level aliases so you can type less:

ShorthandEquivalent
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>:/pathRead a remote file
db9 rm <db>:/pathRemove a remote file
db9 mv <db>:/src <db>:/dstMove/rename a remote file
db9 sh <db>db9 fs sh <db>
db9 cp <src> <dst>db9 fs cp <src> <dst>
db9 ls <db>:/pathdb9 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.

SubcommandDescription
db9 db inspectOverview metrics dashboard
db9 db inspect queriesQuery samples and performance
db9 db inspect reportCombined summary + queries report
db9 db inspect schemasList database schemas
db9 db inspect tablesList database tables
db9 db inspect indexesList database indexes
db9 db inspect slow-queriesSlow queries sorted by p99 latency
Terminal
# Overview metrics
db9 db inspect <db>
# Subcommands
db9 db inspect <db> queries # query samples and performance
db9 db inspect <db> report # combined summary + queries report
db9 db inspect <db> schemas # list database schemas
db9 db inspect <db> tables # list database tables
db9 db inspect <db> indexes # list database indexes
db9 db inspect <db> slow-queries # slow queries sorted by p99 latency

For production monitoring guidance, see Production Checklist.

Terminal
# List database users
db9 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 user
db9 db users <db> delete --username app_user

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.

Terminal
# Inline
db9 db sql <db> --query "SELECT now()"
# From file
db9 db sql <db> --file ./query.sql
# From stdin
cat ./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 mode
db9 db sql <db> --direct
db9 db sql <db> --direct --dsn "postgresql://..."
# Execute a seed SQL file
db9 db seed <db> ./seed.sql
# Export database schema (and optionally data) as SQL
db9 db dump <db>
db9 db dump <db> --ddl-only
db9 db dump <db> --output-file ./backup.sql

The 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.

Each database has a remote filesystem. Use db9 fs for shell access, file copy, and (optionally) FUSE mounts.

Terminal
# List remote files and directories
db9 fs ls <db>:/path
db9 fs ls --long <db>:/path # long format (permissions, size, mtime)
db9 fs ls --recursive <db>:/path # recursive listing
# Interactive filesystem shell
db9 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 contents
db9 rm <db>:/path/to/file # Remove a file
db9 mv <db>:/old/path <db>:/new/path # Move or rename
db9 tailf <db>:/logs/app.log # Follow remote file appends
# Upload / download (scp-like)
db9 fs cp ./local.txt <db>:/remote/path/local.txt
db9 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-only
db9 fs mount <db> "$HOME/mnt/mydb" --cache-ttl 30
db9 fs mount <db> "$HOME/mnt/mydb" --multipart-threshold 16777216 # 16 MB
db9 fs mount <db> "$HOME/mnt/mydb" -f # foreground
db9 fs mount <db> "$HOME/mnt/mydb" --write-async # client async writeback (alias: --writeback); close() seals to local journal, drains opportunistically — not a remote-commit promise
db9 fs mount <db> "$HOME/mnt/mydb" --include '*.md' # sync only .md files
db9 fs mount <db> "$HOME/mnt/mydb" --include '*.rs' --exclude 'target/**'
db9 fs mount <db> "$HOME/mnt/mydb" --no-ignore # disable .fuseignore

A 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).

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.

Terminal
# Watch all events on a database
db9 fs watch <db>:/
# Watch events under a specific path
db9 fs watch <db>:/data/
# Poll every 5 seconds (default: 1) — applies only to the polling fallback
db9 fs watch <db>:/ --interval 5
# Output JSON lines (for piping to other tools)
db9 fs watch <db>:/ --json

With 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:

Output
[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=1790005227835000000

With --json, each line is an object with the same three values:

JSON
{"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):

JSON
{"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.

Follow a remote file and print appended content, similar to tail -f:

Terminal
# Follow a log file (prints last 10 lines, then streams new content)
db9 fs tailf <db>:/logs/app.log
# Show last 50 lines before following
db9 fs tailf <db>:/logs/app.log --lines 50
# Custom polling interval (default: 1 second)
db9 fs tailf <db>:/logs/app.log --interval 2

tailf 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.

Read stdin, echo it to stdout, and write it to a remote file — like Unix tee but targeting the database filesystem:

Terminal
# Pipe command output to a remote file
echo "hello" | db9 fs tee <db>:/logs/out.txt
# Append instead of overwriting
cat local.txt | db9 fs tee -a <db>:/logs/out.txt
FlagDefaultDescription
-a, --appendoffAppend 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).

The interactive shell (db9 fs sh) supports a POSIX-like command set:

CategoryCommands
File opsls, cat, cp, mv, rm, touch, mkdir, stat, find, tree, diff, patch
Text processinggrep, head, tail, sort, uniq, cut, wc, tr, rev, tee, jq
Navigationcd, pwd, basename, dirname
Shellecho, printf, read, export, set, test, alias, source, env, date, sleep, seq
Control flowif/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.

Manage local migration files and apply them to a database. Default directory is ./migrations.

Terminal
# Create a new migration file
db9 migration new create_users
# List local migration files
db9 migration list
# See applied vs pending
db9 migration status <db>
# Apply pending migrations
db9 migration up <db>

All migration subcommands accept --dir <path> to override the default ./migrations directory.

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.

Terminal
# Create a branch from an existing database
db9 branch create <db> --name feature1
db9 branch create <db> --name feature1 --show-secrets # print password + connection string
db9 branch create <db> --name feature1 --show-password # print password only
db9 branch create <db> --name feature1 --show-connection-string # print connection string only
# Point-in-time branch (PITR) — branch from a specific past timestamp
db9 branch create <db> --name rollback --snapshot-at 2026-03-22T06:00:00Z
# List branches of a database
db9 branch list <db>
# Delete a branch database (prompts unless you pass -y/--yes)
db9 branch delete <branch_db>
db9 branch delete <branch_db> --yes

The --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.

Schedule SQL with pg_cron (extension required). Cron commands live under db9 db cron.

SubcommandDescription
db9 db cron listList all cron jobs
db9 db cron createCreate a cron job
db9 db cron deleteDelete a job by ID or name
db9 db cron historyShow job execution history
db9 db cron enableEnable a disabled job
db9 db cron disableDisable a job
db9 db cron statusShow job status
Terminal
# List jobs
db9 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 / status
db9 db cron <db> history --job <job_id_or_name> --limit 20
db9 db cron <db> status
# Enable / disable / delete by job id or job name
db9 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.

Serverless functions let you deploy and run JavaScript/TypeScript code that executes against your database.

SubcommandDescription
db9 functions listList functions in a database
db9 functions createCreate a new function
db9 functions updateUpdate an existing function by name or ID
db9 functions invokeInvoke a function
db9 functions historyList recent runs, or show details of a specific run
db9 functions logsShow logs for a specific run
db9 functions secrets listList all secrets (names only)
db9 functions secrets setCreate or update a secret
db9 functions secrets deleteDelete a secret
Terminal
# 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 source
db9 functions create my-func --db myapp --ts
# Create with execution limits
db9 functions create my-func --db myapp \
--limits-json '{"timeout_ms":60000,"memory_mb":128}'
db9 functions create my-func --db myapp --limits-file ./limits.json
db9 functions create my-func --db myapp --timeout 30000
# Bind secrets to a function
db9 functions create my-func --db myapp --secret API_KEY=my_api_key
# Grant filesystem access to a function
db9 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.js
db9 functions update my-func --db myapp -f ./index.js --timeout 60000 --secret NEW_KEY=my_new_key
db9 functions update my-func --db myapp -f ./index.js --visibility private
db9 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 function
db9 functions invoke my-func --db myapp
db9 functions invoke my-func --db myapp --payload '{"key":"value"}'
# View run history and logs
db9 functions history my-func --db myapp -n 50
db9 functions history my-func <run_id> --db myapp
db9 functions logs my-func <run_id> --db myapp
# Manage secrets
db9 functions secrets list --db myapp
db9 functions secrets set MY_SECRET --db myapp --value "secret-value"
db9 functions secrets set MY_SECRET --db myapp --value-stdin
db9 functions secrets delete MY_SECRET --db myapp

The --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.

db9 share is a shorthand for creating a database-scoped token. It creates the token and prints a ready-to-use connection string.

Terminal
# Read-only share (default), 7-day expiry
db9 share my-app
# Read-write share
db9 share my-app --rw
# Custom expiry (30 days)
db9 share my-app --expires 30
# Custom token name
db9 share my-app --name team-token
FlagDefaultDescription
--rwoffGrant read-write access (default: read-only)
--expires <days>7Token expiry in days
--name <name>share-<db>-YYYYMMDDCustom 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.

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.

Terminal
# Open explorer for a database
db9 explore mydb
# Custom port
db9 explore mydb --port 8080
# Don't auto-open the browser
db9 explore mydb --no-open
# Use cached assets without checking for updates
db9 explore --no-download
# Force re-download even if cached
db9 explore mydb --force-download
FlagDefaultDescription
--port <port>7979Local port (env: DB9_EXPLORER_PORT)
--no-openoffSkip automatic browser open
--no-downloadoffUse cached assets, skip update check
--force-downloadoffRe-download assets even if cached

Create and manage API tokens for CI/CD pipelines, automation, and agent workflows.

Terminal
# 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-agent
db9 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:ro
db9 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 list
db9 token list --all
# Revoke a token (prompts unless you pass -y/--yes)
db9 token revoke <token_id>
db9 token revoke <token_id> --yes

Store created tokens in a secret manager. See Production Checklist for token security guidance.

Generate types from the live schema (prints to stdout). Available languages: TypeScript and Python.

Terminal
# TypeScript
db9 gen types <db> --lang typescript --schema public > db9.types.ts
# Python
db9 gen types <db> --lang python --schema public > db9_types.py

db9 onboard installs or updates the DB9 skill into supported local coding agents. It does not require login and does not send tokens anywhere.

Terminal
# Interactive wizard
db9 onboard
# Non-interactive
db9 onboard --yes --all
db9 onboard --yes --agent codex --agent claude --scope user
# Safety / introspection (zero filesystem changes)
db9 onboard --dry-run
db9 onboard --print-locations
# Advanced: custom skill source
db9 onboard --skill-url https://db9.ai/skill.md
db9 onboard --skill-path ./SKILL.md
db9 onboard --force

Supported agents and default install locations:

Agent--scope user--scope projectNotes
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.mdGeneric agent-compatible directory

For agent workflow patterns, see Agent Workflows.

Common errors and how to resolve them. Messages are printed to stderr; … marks a variable part.

MessageCauseResolution
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 notRun 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 deletedRun db9 list to see available databases
Error 403: Read-only token cannot perform write operations or Error 403: Scoped tokens cannot perform this operationThe token’s --scope does not allow the operationUse a token with the needed scope, or an unscoped token (db9 token create)
Connection failed: error sending request for url (…)API endpoint unreachableCheck network; verify the --api-url flag or DB9_API_URL env var
Error 429: …Too many requests; the message depends on the endpointWait and retry; implement exponential backoff in scripts
Error 409: Database name already exists for this accountDuplicate database nameChoose 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 stateCheck 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 databasesRun 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 connectionVerify the database is active; check fs_websocket_url with db9 db status <name> --json

db9 follows standard Unix exit code conventions for use in shell scripts and CI/CD pipelines.

CodeMeaningExample trigger
0SuccessCommand completed without errors (including --help and --version)
1Runtime errorThe command parsed, but failed — database not found, SQL error, API error. See stderr
2Usage errorThe 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:

Terminal
db9 create --name mydb
if [ $? -ne 0 ]; then
echo "Database creation failed" >&2
exit 1
fi
# Or inline
db9 create --name mydb || { echo "Failed"; exit 1; }

Capturing error output:

Terminal
output=$(db9 db sql mydb -q "SELECT 1" 2>&1)
if [ $? -ne 0 ]; then
echo "Error: $output" >&2
exit 1
fi

Symptom: Not logged in. … or Session expired. … errors.

Terminal
# Check current auth status
db9 status
# Re-authenticate interactively
db9 login
# Use an API key directly (CI/CD)
export DB9_API_KEY=your-token
db9 list
# View the credentials file
cat ~/.db9/credentials
# List all tokens
db9 token list

Symptom: Connection failed: error sending request for url (…) or timeouts when running any command.

Terminal
# 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 command
db9 --api-url https://db9.internal.example.com list
# Set for the shell session via environment
export DB9_API_URL=https://db9.internal.example.com

If behind a corporate proxy, ensure HTTPS_PROXY or https_proxy is set in your environment before running db9 commands.

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:

Terminal
db9 token create --name full-access
export DB9_API_KEY=<new-token>

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.

Terminal
# Check current state
db9 db status mydb

States and meanings:

StateDescription
CREATINGInitial provisioning in progress (usually < 30s)
CLONINGBranch copy in progress
ACTIVEReady for connections
DISABLINGDeletion in progress
DISABLEDDeleted or suspended
CREATE_FAILEDProvisioning failed — delete and recreate

For branch databases, poll until active:

Terminal
while [ "$(db9 db status mydb --json 2>/dev/null | jq -r .state)" != "ACTIVE" ]; do
echo "Waiting for ACTIVE state…"
sleep 2
done

Symptom: Failed to build fs transport: … (or, with --ws-url, Failed to connect or authenticate: …) when using db9 fs commands.

Terminal
# Verify the database is ACTIVE
db9 db status mydb
# Check the WebSocket URL is present
db9 db status mydb --json | jq .fs_websocket_url

If using the TypeScript SDK on Node.js 18–20, install the ws package:

Terminal
npm install ws

Then pass it as the WebSocket option when creating the client — see Filesystem (client.fs).

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.

Terminal
db9 -v list
db9 -v db sql mydb -q "SELECT 1"
RUST_LOG=debug db9 list
  • 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