CapyDB/ docs
Reference

CLI

The capydb CLI links local apps to projects, writes env files, and runs every project operation from the terminal.

Install

Homebrew (macOS/Linux):

brew install capydatabase/tap/capydb

Curl installer (verifies the release checksum, installs to /usr/local/bin or $CAPYDB_INSTALL_DIR):

curl -fsSL https://raw.githubusercontent.com/capydatabase/capydb-cli/main/scripts/install.sh | sh

With go install:

go install github.com/capydatabase/capydb-cli/cmd/capydb@latest

Release archives are built for macOS, Linux, and Windows. Tagged releases also publish checksums, SBOMs, the Homebrew cask, and a multi-platform (amd64/arm64) container image:

docker run --rm ghcr.io/capydatabase/capydb-cli:latest --version

Global flags

Every command accepts:

  • --output text|json (-o) - human-readable text or machine-readable JSON. In JSON mode stdout carries only the JSON document, and lists always marshal as [], never null
  • --api-url - CapyDB API base URL (defaults to https://capydb.dev/api/capydb)
  • --api-key - organization or project-scoped API key (or set CAPYDB_API_KEY)
  • --app-url - CapyDB app URL for browser-based login and dashboard links (or CAPYDB_APP_URL)

Without a saved login or key, commands fail fast with no api key available; pass --api-key, set CAPYDB_API_KEY, or run 'capydb login' instead of hanging.

Commands that queue async jobs (create, preview create|delete|reset, backups create, import, restore, extensions enable|disable, projects retry|delete, roles app enable|rotate, integrations sync, upgrade minor|major|confirm|rollback, jobs get) accept --wait plus --wait-timeout (default 30m). CAPYDB_HTTP_TIMEOUT (a Go duration such as 45s or 2m) overrides the API and upload timeouts.

Exit codes

CodeMeaning
0success
1generic error
2usage or validation error
3authentication or authorization error (HTTP 401/403, missing credentials)
4resource not found (HTTP 404/410)
5conflict or failed precondition (HTTP 409/412/428), including a project or preview database that another operation holds
6timeout (HTTP 408/504, --wait-timeout expiry)

Auth

capydb login

Opens a browser device-login flow, authorizes against the active dashboard organization, and saves a CLI key locally.

  • --no-open - print the authorization URL without opening a browser
  • --name - human-readable name for the CLI key
  • --device-name - device label stored with the key
  • --expires-in - key lifetime such as 24h, 7d, 30d, or an RFC 3339 timestamp

capydb logout

Clears saved CLI authentication.

capydb whoami

Shows the current CLI identity (org, key, source).

capydb status

Shows saved auth, the local project link, and optionally remote status:

  • --remote - check the API and the linked project
  • --usage - what the project uses against its plan, in plain language: plan and billing status, storage and connections against their limits, active previews, retained backups and their total size, with a note when storage or connections pass 80%. Implies --remote; needs a linked project or --project. A paused database is not read (reading its size would wake it) - the storage limit is still shown
  • --project - project id, slug, or name for remote status

capydb doctor

Checks config, API reachability, auth, the local project link and whether its env file still has the database variables (env_vars), psql availability, env keys that point at different databases in different files, database configuration in the repo, and the live migration history, in one pass. Non-zero exit when any check fails - useful as the first command in a broken environment.

  • --fix - apply the mechanical fixes first, then run the checks. Fixes that only add something run without asking: missing database env vars are added to the linked env file (existing values are never overwritten), drizzle-kit configs get schemaFilter: ["public"] and the direct URL for their credentials, Prisma schemas get directUrl = env("DIRECT_URL"). Fixes that remove something - the link to a project that no longer exists, database vars in other env files that shadow the linked one - are asked one by one on a terminal and skipped without one. Everything else (auth, psql, pooler settings in code, the migration history) is listed as manual.
  • --yes - with --fix, apply the removals without asking

capydb config show

Prints the resolved configuration. The API key is shown only as a ****abcd fingerprint.

capydb version [--check]

Build info. --check compares against the latest GitHub release (5s timeout, degrades to a warning offline).

capydb orgs list / capydb orgs switch <org-id|slug>

The CLI stores credentials per organization with an active-org pointer; switch changes which one subsequent commands use.

Compatibility aliases: capydb auth login|logout|whoami.

Projects and linking

capydb projects list

Lists the organization's projects (id, name, slug, region, state).

capydb projects set-environment <production|non_production>

Sets a project's environment label. non_production unlocks overwrite-restore (capydb restore --target-kind project); production keeps it locked. Changing the environment also resets the sleep policy to that environment's default (production: always on; non-production: pause when idle) unless you set it explicitly afterwards. --project.

capydb projects always-on <on|off>

Sets a project's sleep policy. on keeps the database awake instead of pausing it when idle, so no connection ever waits for a resume; off returns it to pausing when idle. Production projects are always on by default. Preview databases pause when idle regardless of this setting. --project.

capydb projects delete <project>

Deletes a project: its database, preview databases, and backups. This cannot be undone. The project is named explicitly (id, slug, or name); the linked project is never used implicitly.

  • Confirm by retyping the project name (or yes) at the prompt, or pass --confirm in scripts (--yes is accepted too).
  • A production project also needs a delete approval from an organization admin: open the project's Settings page in the dashboard, create a delete approval, and pass the token with --approval-token or CAPYDB_APPROVAL_TOKEN. It works once, for 10 minutes. Without it the command stops before deleting anything and prints the settings page URL. Non-production projects need only the confirmation.
  • --wait, --wait-timeout - follow the deletion job

If the current directory was linked to the deleted project, run capydb unlink and remove its env vars afterwards.

capydb projects retry <project>

Re-runs provisioning for a project whose provisioning failed: the same database, with the same credentials, is created again, so env files keep working. Repeating it returns the provisioning job already in flight. A project that failed in a later operation already has its database and is refused with an explanation. Needs an organization admin or an organization-wide API key. --wait, --wait-timeout.

capydb regions

Lists the regions open for new projects: the region id (the value --region takes, such as eu-north-1), its display name, and where its nodes run. capydb regions list is the same. -o json returns {"regions": [{"id", "display_name", "location"}]}. Deprecated region names (hel1) are still accepted by --region.

capydb postgres-versions

Lists the Postgres majors new databases can be created on, oldest first, with each one's release channel - previous, stable (the default), current, or beta (an upstream beta offered for evaluation only: not production ready) - and whether it is the default. -o json returns {"versions": [...]}. See version upgrades.

capydb create

Creates a project and links the current directory to it (power-user path; the dashboard is the default onboarding).

  • --name, --slug, --region - project naming and placement (--region takes a region id from capydb regions)
  • --environment - environment label: production (default) or non_production (unlocks overwrite-restore)
  • --postgres-version - Postgres major version: 16, 17, 18, or 19 while it is offered as a beta (platform default when omitted; see capydb postgres-versions). Previews and restores inherit it; only a major upgrade changes it. The summary shows the major with its channel, plus the beta warning for a beta database
  • --source-url - the database you will import from. Without --postgres-version, the project gets that database's major (read with one read-only query), raised to 16 for older sources; a source newer than 18 stops the create, since a dump never restores into an older major. An explicit --postgres-version older than the source is allowed with a warning. Without --source-url, create points out a DATABASE_URL / DIRECT_URL in the target env file that belongs to another provider, but does not connect to it.
  • --env-file - target env file
  • --yes - non-interactive; let CapyDB pick a region when none is specified
  • --template - apply a starter after the project is created and linked: drizzle-starter (users and posts with a foreign key and sample rows; follow with capydb init drizzle) or auth-starter (users, OAuth accounts, sessions and hashed verification tokens, with one demo user). empty (the default) applies nothing. Schema and seed run in one transaction; if that fails, the project still exists, nothing was applied, and the SQL is saved as capydb-template-<name>.sql for capydb seed

Links the current directory to an existing project. Accepts a project id, slug, or name via --project; prompts interactively on multiple matches; reuses .capydb/project.json when present.

  • --project - project id, slug, or name
  • --env-file - target env file

It detects the local app profile (Next.js, SvelteKit, Remix, Django, Rails, Go, generic Node/Python; Prisma, Drizzle, pg, pgx, SQLAlchemy, Active Record), writes DATABASE_URL (pooled for JS/TS stacks, direct for Go, Python, and Ruby), DIRECT_URL and DATABASE_DIRECT_URL (the direct connection, for migrations - DIRECT_URL is the name Prisma's directUrl and most ORM guides use), and DATABASE_POOL_URL into the right env file, saves a non-secret link in .capydb/project.json, and gitignores both .capydb/ and the credential-bearing env file. Monorepos: nested app directories are detected and prompted for.

An existing value that differs from the CapyDB one (say, the previous provider's DATABASE_URL) is prompted for on a terminal and replaced with a warning in CI; --overwrite-env replaces without asking.

capydb connect is no longer an alias of link - it opens psql (see capydb psql under Database access).

Removes the local project link.

capydb env pull

Refreshes local env vars from the linked project (after a rotation, restore, or import). Values that already point at the same CapyDB host are refreshed silently; a value pointing anywhere else - typically a DIRECT_URL left over from a previous provider - is prompted for on a terminal and replaced with a warning in CI.

  • --env-file - override the target env file

When the project has its runtime login (capydb roles app enable), env pull - like link and create - also writes DATABASE_APP_URL (the same pooled-or-direct choice DATABASE_URL makes for your stack) and DATABASE_APP_POOL_URL (always pooled) with app_user's credentials.

capydb env sync vercel|netlify

Connects the project to a Vercel project or Netlify site and pushes DATABASE_URL and the other connection variables to it, then waits for the push. CapyDB stores the token encrypted, so the variables are pushed again whenever the credentials rotate - a one-off copy would go stale. Run it again to re-push or to replace the token. Redeploy for running deployments to pick the values up.

  • vercel: the project comes from --vercel-project <id|name> or the directory's .vercel/project.json (written by vercel link), a team project's team from --team or that file; the token from --token or VERCEL_TOKEN
  • netlify: the site comes from --site <id> or .netlify/state.json (written by netlify link); the token from --token or NETLIFY_AUTH_TOKEN
  • --preview-branches - also give each preview/branch deployment its own preview database
  • --wait (default on; --wait=false to return after queueing), --wait-timeout, --project

See the Vercel and Netlify guides.

Ephemeral databases

A throwaway database with no account - see the guide. Destroyed after 72 hours unless claimed.

capydb ephemeral create

Creates an ephemeral database without logging in (when an API key is configured - --api-key, CAPYDB_API_KEY, or a login - it is sent, and unclaimed databases count against your account instead of your network address), waits for it to come up, and writes its connection strings to the env file the same way capydb create does. The claim token is saved to .capydb/ephemeral.json (mode 0600, git-ignored) before anything else can fail: it is shown once and cannot be recovered. Refuses to run when the directory already has an unexpired ephemeral database on record.

  • --name - display name (a name is generated when omitted)
  • --region - region id, e.g. eu-north-1
  • --postgres-version - 16, 17, 18, or 19 while offered as a beta
  • --env-file, --overwrite-env - as for capydb create
  • --no-env - touch no env file and print the pooled and direct connection strings instead
  • --wait-timeout - how long to wait for the database (default 5m)

With -o json, stdout carries the database and the env var names written; connection strings appear only with --no-env, and the claim token never does.

capydb ephemeral status

State and time remaining. --claim-url also prints the browser claim link, which embeds the secret claim token.

capydb ephemeral claim

Keeps the database: logs in if needed, attaches it to your organization as a normal project, links the directory to it, and deletes the spent claim token. Data and connection strings do not change. Needs an active plan and room under the plan's project limit.

capydb ephemeral destroy

Destroys the directory's unclaimed ephemeral database now instead of waiting for it to expire, and frees its slot. Needs no account: the claim token in .capydb/ephemeral.json authorizes it, and the file is removed afterwards. The data is gone; a database you already claimed is a project - delete it from the dashboard instead.

Previews

capydb preview list

Lists preview databases with state, mode, TTL expiry, and connection URLs. --project to target a specific project.

capydb preview create

  • --mode - empty or clone
  • --name - preview name
  • --ttl-hours - TTL in hours (1–168, default 24)
  • --wait - block until the create job finishes
  • --project

capydb preview reset

Re-clones or re-empties a preview. --preview (id or name), --wait, --project.

capydb preview delete

--preview (id or name), --wait, --project.

capydb preview extend <preview-id>

  • --ttl-hours - new TTL in hours (1–168)

Backups, restores, imports

capydb backups list / capydb backups create

list marks an expired backup - its file is no longer in storage, so it is listed as a record and cannot be restored - as expired*.

  • create: --label (optional), --wait, --project

capydb backups schedule get|set|disable

Manages the project's daily backup schedule. All three take --project.

  • set: --hour (UTC hour, 0-23), --minute (0-59), --retention-days (1-365, server default when omitted), --label (optional label for scheduled backups)

capydb export

Queues a logical export (pg_dump custom-format archive) of the project database, waits for the job, and downloads the artifact. Exports stay downloadable for 7 days.

  • --output - destination file (default <project>-<timestamp>.dump)
  • --no-download - queue and wait, but skip the download
  • --wait-timeout, --project

capydb export list

Lists the project's exports with state, size, and expiry. --project.

capydb export download

Downloads a completed export within its 7-day window.

  • --export - export id (see capydb export list)
  • --output, --project

capydb import

Imports data into the project's live database - the same blast radius as an overwrite restore, so it requires --confirm or, on an interactive terminal, retyping the project name (or yes) at the prompt.

  • --source-url - source Postgres connection string (use the provider's direct endpoint - Neon -pooler hosts and Supabase's transaction pooler on port 6543 are rejected)
  • --file - path to a pg_dump file to upload and import (custom format recommended: pg_dump -Fc); mutually exclusive with --source-url
  • --recreate - drop and recreate the target database before import. The existing database is backed up first (pre-import-<job id> in capydb backups list); the import stops with nothing dropped if that backup fails
  • --confirm - confirm loading the imported data into the live database (for non-interactive/CI use)
  • --follow - near-zero-downtime import: base-copy then stream the source's changes until capydb import cutover (source needs logical replication; incompatible with --file and --recreate)
  • --wait, --project
  • --from <provider> - fix up --source-url for a provider before anything is sent, printing every change: neon (the -pooler endpoint becomes the direct one; --from-neon is shorthand), supabase (transaction pooler port 6543 becomes the session pooler 5432 on the same host), planetscale (PgBouncer port 6432 becomes 5432), railway and render (their private hostnames stop with where to find the public URL), rds. Every preset adds sslmode=require when the URL leaves TLS to libpq's default, and lists the provider's traps (logical replication for --follow, security groups, the IPv6-only Supabase direct host). Also on import preflight
  • --data-only - see Data-only import below
  • --from-supabase-dump <file> - see Restoring a Supabase dump below

Imports run from CapyDB's network, so a source on your machine or a private network cannot be imported by URL. localhost, a unix socket, private (RFC 1918 / IPv6 ULA), CGNAT/Tailscale (100.64.0.0/10), link-local, *.internal, and *.local hosts - literally or by what the name resolves to on your machine - are stopped before anything is sent, with the two commands that work instead:

pg_dump -Fc --no-owner --no-privileges -d "$SOURCE_URL" -f source.dump
capydb import --file source.dump --project <project>

The same check compares your local pg_dump with the source's Postgres major and says which client to use when they differ.

For a Supabase source with SUPABASE_ACCESS_TOKEN set, the CLI reads the project's pooler host from the Supabase Management API and warns when the connection string uses the wrong aws-0 / aws-1 prefix, the IPv6-only direct host, or the transaction pooler port 6543, naming the session pooler (<host>:5432) to use.

Data-only import

capydb import --data-only --source-url <url> copies rows into the tables your migrations already created on the project, parents before children by the project's foreign keys. pg_dump writes tables alphabetically, so a data-only dump fails the moment a child sorts before its parent, and pg_restore --disable-triggers needs a superuser the project role is not. This path runs on your machine - it connects to the source and to the project's direct URL and streams COPY between them - so a localhost or private-network source works too.

  • The source is read in one REPEATABLE READ snapshot; the project is written in one transaction - a failure leaves nothing behind.
  • Target tables must be empty; it never merges. Tables missing from the source are left empty, source-only columns are skipped, and target columns missing from the source get their default - all reported.
  • A foreign-key cycle is loaded with its DEFERRABLE constraints checked at commit; a cycle without one stops before writing and names the tables.
  • During the load, user triggers are disabled (the rows already carry what those triggers computed) and FORCE ROW LEVEL SECURITY is lifted; both are restored in the same transaction. Generated columns are left to the project.
  • Serial and identity sequences continue from the source's position; materialized views are refreshed and the tables analyzed afterwards.
  • --dry-run prints the load order and the notes without writing. --confirm or the typed-name prompt is required, as for every import.

Restoring a Supabase dump

capydb import --from-supabase-dump <file> restores a Supabase pg_dump -Fc file in the order a project role can apply it, as one transaction:

  1. the capyrls compatibility shim (auth.uid(), auth.jwt(), ...), so column defaults and functions that call it resolve
  2. the app schemas' tables, types and functions
  3. the data
  4. indexes, constraints and triggers
  5. FORCE ROW LEVEL SECURITY and the converted policies

Supabase-managed schemas (auth, storage, realtime, ...), the dump's own policies (step 5 replaces them), grants to the PostgREST roles, publications and event triggers stay behind, as do foreign keys into auth.users - each one is listed. extensions. qualifications are rewritten to public. when the project keeps its extensions there. It stops before writing when the dump uses an extension the project has not enabled, or when the project already has tables.

  • --uid-type text - for identity providers whose user ids are not uuids (see capydb migrate rls)
  • --rls-out - where the policy bundle and its report go (default capyrls/); the report lists the session context your app must set
  • --dry-run, --confirm, --project

Needs pg_restore (at least the dump's Postgres major) and psql on this machine. See the Supabase guide.

capydb import follow-status

Shows progress of an in-progress follow import (phase, replication lag). --wait, --project.

capydb import cutover

Finishes a follow import: drains the stream and flips the project live (stop source writers first). Replacing the live database requires --confirm or the interactive typed-name confirmation. --wait, --project.

capydb import follow-abort

Cancels an in-progress follow import and cleans up the source replication slot. --wait, --project.

capydb import preflight

Checks a source database against the project before importing - size vs plan, Postgres major (no downgrades), extension availability - without changing anything.

  • --source-url, --project
  • --from <provider> / --from-neon - the same provider presets as capydb import

Also on the preflight:

  • a note when your local pg_dump major differs from the source's (it matters when you dump locally for import --file: an older pg_dump refuses a newer server, a newer one can write settings an older restore target rejects);
  • Supabase pooler-host advice as for capydb import; without SUPABASE_ACCESS_TOKEN it explains where to copy the Session pooler string;
  • a source CapyDB cannot reach is stopped the same way as for capydb import, pointing at capydb migrate scan --source-url for a local check.

capydb restore

  • --backup-key - backup to restore
  • --restore-time - RFC 3339 timestamp for point-in-time restore
  • --restore-point - labelled restore point id (alternative to the two above)
  • --target-kind - project, preview, or new_preview (inferred from --preview/--preview-name; defaults to new_preview)
  • --preview - existing preview id or name (target-kind preview)
  • --preview-name - name for a new preview (target-kind new_preview)
  • --ttl-hours - TTL for the new preview
  • --confirm - confirm overwriting the project database non-interactively (without it, an interactive terminal prompts you to retype the project name); the overwrite also needs --approval-token
  • --approval-token - a single-use project.restore_overwrite approval an org admin created on the project's Backups page in the dashboard (default: $CAPYDB_APPROVAL_TOKEN). The CLI no longer mints one: the control plane refuses approvals from API keys. Without it the command stops before the restore and prints the Backups page URL
  • --allow-unverified - allow restoring from a backup that has not passed verification
  • --recreate - drop and recreate the project database before a backup restore. The existing database is backed up first (pre-restore-<job id>); the restore stops with nothing dropped if that backup fails
  • --wait, --project

A --restore-time later than the latest restorable point is clamped to that point instead of refused. The command then prints the requested and effective times (on stderr with -o json), and the --wait summary names the effective time.

capydb restore-points list|create|delete

  • create: --label (required), --kind (backup or pitr, inferred), --backup-key, --pitr-time (defaults to now), --note
  • delete: --id

Migrations from other providers

All capydb migrate subcommands work without CapyDB credentials - they operate on your repo and your old database.

capydb migrate scan

Classifies a repository (read-only, no network) across the migration axes - source provider, auth system, data-access layer - and emits a per-database migration plan.

  • --portfolio - directory of sibling repos to check for other consumers of the same databases

capydb migrate deps

Swaps provider-specific packages for their standard-Postgres equivalents in package.json.

  • --dir - project directory
  • --dry-run - report without writing

capydb migrate codemod neon

Rewrites Neon serverless-driver usage to plain postgres/pg. Dry-run by default.

In a repo that uses drizzle's neon-http driver, db.batch([...]) calls whose statements are written inline on the client are rewritten to a transaction that runs the same statements, in order, all or nothing - which is what a neon-http batch is:

const [users, post] = await db.transaction(async (tx) => {
  const r0 = await tx.select().from(usersTable);
  const r1 = await tx.insert(posts).values(values).returning();
  return [r0, r1] as [typeof r0, typeof r1];
});

Batches built from variables, spreads, statements containing await, a client reached through a property (this.db), or files the codemod cannot read with certainty (regex literals) are listed with the reason instead.

  • --write - apply the changes

capydb migrate rls

Converts Supabase row-level-security policies to portable, vanilla Postgres. Reads a supabase/migrations directory (found automatically from a repo root), a schema dump, or any SQL files; writes an ordered SQL bundle plus a report describing the session context your application must set. See the full guide.

  • --mode - vanilla (default: app.* session-setting accessors) or supabase-compat (an auth.* shim; policies port verbatim)
  • --role-model - single (default: FORCE row security, app connects as owner) or split (request traffic runs as a runtime role RLS applies to; on CapyDB that is the project's app_user, which must be enabled first with capydb roles app enable - the command reminds you - and the bundle creates no roles; with --target postgres it creates app_user/app_service)
  • --target - capydb (default) or postgres, for a bundle you will apply to another Postgres where you manage roles
  • --keep-for-all - keep FOR ALL policies instead of splitting them per command
  • --no-service-escape - single role model: skip the service escape (app.role = 'service' in vanilla mode, claims with "role": "service_role" in compat mode)
  • --uid-type - uuid (default) or text: the type the user-id accessor returns; use text when your user ids are not uuids (Clerk's user_...) - see user ids that are not uuids
  • --out - output directory (default capyrls)

capydb migrate verify

Watches the OLD database after cutover to confirm nothing still writes to it.

  • --source-url - the old database
  • --watch, --interval - keep checking on a cadence
  • --env-file - env files naming the old database (repeatable)

Jobs

capydb jobs get

  • --job-id - job to inspect
  • --wait - block until terminal state before printing

capydb jobs list

Lists a project's recent jobs, newest first.

  • --limit - maximum number of jobs to return (server default when omitted)
  • --project

Database access

capydb connection-string

Prints only the URL - script-friendly.

  • --pooled - pooled (pgbouncer) URL instead of direct
  • --preview - preview database id
  • --project

capydb psql [-- <extra psql args>]

Opens an interactive psql session on the linked project, --project, or --preview, over the direct connection unless --pooled is set. A paused database resumes on connect. Arguments after -- go to psql unchanged. Needs psql from libpq 16 or newer.

Alias: capydb connect (through CLI v1.8.0 connect aliased capydb link).

capydb connect
capydb connect --pooled -- -c "select now()"

capydb seed [file.sql]

Loads seed data into the linked project, --project, or a --preview.

  • a .sql file runs through psql in one transaction (COPY ... FROM stdin and meta-commands work; a failing file leaves nothing behind)
  • --run "<command>" runs any seeder - drizzle-seed, Prisma, a script - with DATABASE_URL, DATABASE_DIRECT_URL, DIRECT_URL, DATABASE_POOL_URL, CAPYDB_DATABASE_URL, POSTGRES_URL and the link's own variable names all set to the target's direct URL (already-set values are replaced, so the seed cannot reach another database by accident)
  • with neither, it runs the package.json db:seed or seed script, Prisma's prisma.seed, or the first of seed.sql, supabase/seed.sql, db/seed.sql, database/seed.sql, prisma/seed.sql, drizzle/seed.sql
  • a production project needs --confirm-production (or typing the project name at the prompt) and gets a restore point first, so the seed can be undone with capydb restore --restore-point <id>; --no-restore-point skips it. Previews and non_production projects are seeded without asking
  • --dry-run - show what would run and against which database

capydb sql <query>

Runs a query through the bounded SQL runner (15s timeout, 1000-row cap, 20k-char queries).

  • --max-rows - row cap (server default 200 when omitted)
  • --read-only - run inside a READ ONLY transaction, so the server itself refuses every write (DML, DDL, TRUNCATE, SELECT INTO, sequence advancement). Recommended whenever the statement is not meant to change anything - the guarantee comes from the Postgres executor, not from inspecting the statement
  • --allow-unqualified-writes - permit an UPDATE/DELETE with no WHERE, or a TRUNCATE (refused by default)
  • --preview <id> - run against a preview database instead - the place to rehearse a destructive statement first. Preview executions are not recorded in SQL history
  • --json - raw JSON result
  • --project

capydb metrics

Storage/connection usage, resume latency over the last seven days (resumes (last 7 days): 5, p50 148ms, p95 1.2s, max 1.8s), alerts, active and slow queries. --json for the raw payload, including the wake object. Alias: capydb observability.

capydb logs

Shows the project's Postgres log stream: a trailing window by default, or a live tail with --follow (Ctrl-C to stop). In JSON mode a tail emits one JSON document per entry (JSONL). A line that reports a condition shows its SQLSTATE in brackets (ERROR [42P01] relation "x" does not exist); JSON entries carry sqlstate, pid, user and database when the line has them.

  • --hours - trailing window in hours (default 1). Up to 720 (30 days) where the platform keeps a log archive; 168 (7 days) otherwise - windows older than 7 days are served from the archive
  • --limit - maximum entries per fetch (server default when omitted, max 500)
  • --severity - comma-separated severity filter (debug, log, info, notice, warning, error, fatal, panic, detail), e.g. --severity error,fatal
  • --follow (-f) - keep the stream open and print new entries as they arrive
  • --project

Searching. --search, --sqlstate, --since, --until or --cursor switch to a search of the archived logs of the last 30 days, newest first (--severity and --limit still apply; --follow cannot be combined):

  • --sqlstate - comma-separated five-character codes (42P01) or two-character classes (23)
  • --search - case-insensitive substring of the message (up to 200 characters)
  • --since, --until - RFC 3339 times or durations back from now (90m, 12h, 7d); the window defaults to the last 24 hours. An explicit --hours without --since sets the start
  • --cursor - continue from the cursor the previous page printed
capydb logs --sqlstate 23 --since 7d
capydb logs --search deadlock --severity error -o json

Where log search is not enabled the command says so; the stream above keeps working.

capydb advisor indexes

Suggests indexes from the predicates your queries actually filtered on. Each candidate is costed by building it as a hypothetical index, so nothing is created and nothing is written to your database

  • safe to run against production. Requires the pg_qualstats extension, plus hypopg for size estimates; note that enabling pg_qualstats restarts the database.

  • --min-filter - minimum average rows a predicate must filter to be considered (default 1000; lower it on a quiet database)

  • --min-selectivity - minimum average selectivity percentage for a predicate to be considered (default 30)

  • --project

capydb advisor index-hygiene

The other half of index advice: indexes your database pays for on every write and never reads. Reports indexes with no recorded scans, and indexes whose columns are the leading columns of another index on the same table, each with a ready-to-run DROP INDEX CONCURRENTLY statement. Read-only, and it needs no extensions.

UNIQUE, primary-key and exclusion indexes are never listed - they are constraints, not just access paths. Nothing is reported until a week of query statistics has accumulated, because Postgres does not record when an index was created and over a shorter window an index a monthly job uses looks identical to a dead one.

  • --project

Alias: capydb advisor unused-indexes.

Alias for the group: capydb advise.

capydb db lint

Read-only checks for problems that are cheap to fix early and expensive later, each with the statement that fixes it:

RuleSeverityWhat
missing_primary_keywarninga table without a primary key (names a NOT NULL unique constraint that could be promoted)
unindexed_foreign_keywarninga foreign key whose columns do not lead any index - deletes and key updates on the referenced table scan this one
duplicate_indexwarningindexes with the same definition (columns, operator classes, sort order, predicate)
redundant_indexwarningan index whose columns lead a wider index (from advisor index-hygiene)
unused_indexinfono recorded scans over the observation window (from advisor index-hygiene)
table_bloatinfodead rows are over 20% of a table with at least 10,000 of them
  • --exit-code - exit 1 when a warning is found (for CI)
  • --preview - lint a preview database; the unused- and redundant-index checks need a week of the project's statistics and are skipped there
  • --project

The checks run server-side (GET /v1/projects/{projectID}/lint) as catalog queries in a read-only transaction that read no table data, so a key with only schema:read is enough. A check that cannot run is listed as skipped, with the reason. -o json prints {"findings": [...], "skipped": [...]}.

Schema and code generation

capydb schema dump

Writes the project's schema as canonical JSON - the same document the API serves, stable enough to commit and diff. Stdout by default.

  • --out - write to a file instead of stdout
  • --preview - dump a preview database instead of the project database
  • --project

capydb schema diff

Diffs the live schema against a committed snapshot or against a preview database.

  • --against - baseline snapshot file produced by capydb schema dump
  • --against-preview - baseline preview database id
  • --preview - diff a preview database instead of the project database
  • --exit-code - exit 1 when differences are found (for CI)
  • --project

capydb generate types|zod|drizzle|go|python

Generates typed source from the live schema - TypeScript interfaces, Zod schemas, a Drizzle schema, Go structs, or Python models. Every language is rendered server-side, one implementation shared with the API and the MCP server, so no generator needs a direct database connection. --style and --package are validated by the control plane.

  • --out - output file path (defaults to the generator's suggested filename)
  • --print - print to stdout instead of writing a file
  • --preview - generate from a preview database instead of the project database
  • --style (types) - capydb (default) or supabase, which is compatible with supabase-js generics; (python) - dataclass (default, standard library) or pydantic
  • --package (go only) - package name, default db
  • --watch - keep running and rewrite the file whenever the schema changes; --watch-interval (default 5s) sets how often it looks, backing off to once a minute while nothing changes. A paused database is not read - its schema cannot change until it resumes, and reading it would wake it. With --output json, one JSON line per regeneration
  • --project

See the type generation guide.

capydb init drizzle|prisma|kysely

Scaffolds an ORM wired to the linked project (capydb init --orm <name> is the same):

  • drizzle - drizzle.config.ts on the direct URL, a Drizzle schema generated from the live database, and a src/db client using @capydb/drizzle
  • prisma - Prisma ORM 7: prisma.config.ts pointing migrations and db pull at DATABASE_DIRECT_URL, prisma/schema.prisma with the prisma-client generator, and src/db.ts building the client on @prisma/adapter-pg over the pooled DATABASE_URL. Models come from npx prisma db pull. The printed install command pins @7
  • kysely - src/db/database.types.ts from capydb generate types and a src/db client that maps its Row/Insert/Update types onto Kysely's column types (defaults optional on insert, generated columns not writable), on the pooled DATABASE_URL

Flags: --dir, --force (overwrite existing files), --schema (path of the generated file), --project.

Extensions

capydb extensions list|enable|disable

Manages the project's Postgres extensions. list shows the allowlist with enabled/trusted/version per extension; enable <name> and disable <name> queue async jobs and accept --wait. Disable runs DROP EXTENSION without CASCADE, so it fails (with the dependency error) rather than dropping dependent objects. --project on all three. Aliases: extension, ext.

K/V

Manages the project's K/V store - one per project. Every subcommand takes --project (default: the linked project) and -o json. Alias: capydb kvstore.

The credentials use CapyDB's own names, CAPYKV_REST_URL, CAPYKV_REST_TOKEN and CAPYKV_REDIS_URL (the RESP URL, which embeds the token) - read them with @capydb/kv. Only a SHA-256 hash of the token is stored, so the token and the full RESP URL exist only in the create and rotate-token output.

capydb kv status

Shows the store's id, state, capacity, eviction policy and persistence, or says the project has none ({"kv_store": null} with -o json). States are those in K/V operations. A stopped store was stopped by the platform, not put to sleep, so the state line says why and what brings it back - for org_suspended: the organization is suspended and offline, the store keeps its data and starts again when the suspension lifts.

capydb kv create

Provisions the store and prints its token and RESP URL once.

  • --write-env - write the three variables into the linked project's env file instead of printing the secret parts (the file is checked before the store is created)
  • --env-file - the env file --write-env writes (default: the linked project's; required when the directory is not linked)
  • --wait, --wait-timeout

With -o json the token is part of the JSON document, since that is where a script reads it.

capydb kv credentials

Prints CAPYKV_REST_URL and the RESP URL without its password. The token cannot be read back; rotate-token is the way to get a new one.

capydb kv rotate-token

Mints a new token and stops the old one immediately - there is no grace window. Prints the new token once, or writes it with --write-env / --env-file as create does. Confirm with --confirm or by typing the project name; a non-interactive run without --confirm refuses.

capydb kv flush

Deletes every key. The store, its endpoint and its token stay, and there is no backup to restore from. --confirm (or the typed-name prompt), --wait, --wait-timeout.

capydb kv delete

Deletes the store and its data; the database is untouched. A project holds one store at a time, so a new one can be created once this finishes. --confirm (or the typed-name prompt), --wait, --wait-timeout.

Alerts

capydb alerts list

Lists the project's threshold alerts - open ones plus those resolved in the last 30 days - with kind, severity, observed/limit values, and timestamps. --project.

capydb alerts ack <alert-id>

Acknowledges an alert (idempotent; first acknowledgement time wins). Acknowledging is visual only - it does not silence notifications. --project. Alias: acknowledge.

Credentials

capydb credentials rotate

Rotates the project's database password. With --grace-hours the outgoing credential keeps working for that long (a new database username is issued), so applications can pick the new string up before the old one stops. 0 is an immediate cutover; the maximum is 720 hours.

  • --grace-hours - hours the outgoing credential stays valid (0-720)
  • --confirm - skip the interactive prompt
  • --wait, --wait-timeout (default 30m)
  • --project

See the credential rotation guide.

capydb roles app show|enable|rotate

Manages the project's runtime login, app_user - the split role model's login for request traffic, which owns nothing and cannot bypass row-level security.

  • show - whether the project has it, its username, and when it was created or last rotated (never the password)
  • enable - create it (Postgres 16 or newer). It reads the status first, so a project that already has the role, or a platform that does not offer it yet, is reported instead of queuing a job. Run capydb env pull once the job completes to write DATABASE_APP_URL and DATABASE_APP_POOL_URL
  • rotate - replace its password in place; the old one stops working when the job completes (no grace window), so refresh the env vars right after

--project, -o json; enable and rotate take --wait, --wait-timeout.

Version upgrades

Minor and major releases move very differently - see the version upgrades guide.

capydb upgrade minor

Restarts the database onto the latest available minor (17.4 to 17.5). Minors are binary-compatible, so nothing is migrated - only the server binary changes, at the cost of a brief interruption to open connections. A paused database needs no action: it starts on the new minor when it next resumes.

  • --wait, --wait-timeout (default 30m)
  • --project

capydb upgrade preflight

Checks whether the database can move to a Postgres major. Nothing is changed, so it is safe to run repeatedly. The blocker that matters most in practice is extensions: if one you use has no build for the target major, migrating would leave your schema referencing types and functions that no longer exist.

  • --target-major - the major to evaluate, e.g. 18
  • --wait (default true), --wait-timeout (default 30m)
  • --project

capydb upgrade major

Upgrades the database to a newer Postgres major. It runs the preflight first (the control plane requires a passing one for the same target from the last hour) and starts the upgrade only when the verdict is upgradable. Writes are refused while the data is copied; the connection string does not change. The previous database is kept for 72 hours - see capydb upgrade status.

  • --target-major - the major to upgrade to, e.g. 18
  • --approval-token - a single-use project.upgrade_major approval an organization admin created in the dashboard (default: $CAPYDB_APPROVAL_TOKEN). Without it the command stops before anything runs and prints the settings page URL. Its 10 minutes include the preflight
  • --confirm - skip the typed-name prompt
  • --wait, --wait-timeout, --project

Self-serve major upgrades answer 403 until CapyDB enables them; the command says so.

capydb upgrade confirm / capydb upgrade rollback

confirm finalizes a completed upgrade and deletes the retained database (rollback is no longer possible); rollback returns the project to it, discarding every write since the cutover (delete preview databases first). Each needs its own approval (project.upgrade_major_confirm or project.upgrade_major_rollback) via --approval-token or $CAPYDB_APPROVAL_TOKEN, plus --confirm or the typed-name prompt. Both are accepted until the rollback window closes; afterwards CapyDB confirms on its own. --wait, --wait-timeout, --project.

capydb upgrade status

Shows the major upgrade in flight - the majors it moves between, its state (staging, rollback_available, confirming, rolling_back) and rollback_available_until - or that there is none. -o json returns {"upgrade": ... | null}. --project.

See running a major upgrade yourself.

Audit

capydb audit list

Lists project audit events. --project, --limit N.

API keys

capydb api-keys list|create|revoke

  • create: --name and --scopes are required; --project makes the key project-scoped. The plaintext key is shown exactly once.
  • revoke: by key id.

Webhooks

capydb webhooks list|create|delete|rotate-secret|deliveries

Manages the organization's webhook endpoints. Signing secrets (whsec_...) are shown exactly once on create and rotate; deliveries shows the per-endpoint delivery history.

Notifications

capydb notifications show|set

Shows and changes which notification emails the organization receives. Alert and billing emails always go to the organization's billing email when one is set; the recipient lists add to it. Billing notices cannot be switched off.

  • set --alert-emails on|off - send usage, backup and reachability alert emails
  • set --alert-recipients a@example.com,b@example.com - extra alert recipients (replaces the list; "" clears it; at most 10)
  • set --billing-recipients ... - extra recipients of billing notices, the same way

set changes only the settings passed: it reads the current preferences and sends the full replacement the API requires. Needs an organization admin, or an organization-wide key an admin created. -o json on both.

Misc

capydb studio

Opens the dashboard page for the linked project.

  • --page - overview, connections, studio, previews, backups, or settings (default connections)
  • --print-only - print the URL without opening it
  • --project

capydb integrations env

Prints environment-variable payloads for deployment platforms.

  • --target - dotenv, json, vercel, netlify, or wrangler (default dotenv)
  • --branch - Vercel preview branch for branch-scoped env vars
  • --netlify-context - all, dev, branch-deploy, deploy-preview, production, or branch (default all)
  • --project

--target wrangler prints a wrangler.jsonc fragment carrying the Hyperdrive binding for this project's Cloudflare integration - connection strings stay out of it, since that file gets committed. The wrangler dev local connection string is printed alongside on stderr. Requires an active Cloudflare integration whose Hyperdrive config already exists.

capydb integrations sync vercel|netlify|cloudflare

Pushes the project's connection env vars to an already connected Vercel project, Netlify site or Cloudflare integration again, with the token CapyDB stored when it was connected. Use it after a variable was edited or deleted on the platform, or after a failed push (pushes also happen on their own after credential rotations and restores). A project without that integration, and a push already queued or running, are explained. --wait, --wait-timeout, --project, -o json.

capydb completion bash|zsh|fish|powershell

Shell completion scripts. Release archives and the Homebrew cask ship pre-generated ones.

Local files

  • Global: CLI auth and active organization info live in the user config directory.
  • Local: .capydb/project.json stores the linked project id, chosen env file, and detected profile - no secrets. Secrets stay in the app env file, which the CLI gitignores.

On this page

InstallGlobal flagsExit codesAuthcapydb logincapydb logoutcapydb whoamicapydb statuscapydb doctorcapydb config showcapydb version [--check]capydb orgs list / capydb orgs switch <org-id|slug>Projects and linkingcapydb projects listcapydb projects set-environment <production|non_production>capydb projects always-on <on|off>capydb projects delete <project>capydb projects retry <project>capydb regionscapydb postgres-versionscapydb createcapydb linkcapydb unlinkcapydb env pullcapydb env sync vercel|netlifyEphemeral databasescapydb ephemeral createcapydb ephemeral statuscapydb ephemeral claimcapydb ephemeral destroyPreviewscapydb preview listcapydb preview createcapydb preview resetcapydb preview deletecapydb preview extend <preview-id>Backups, restores, importscapydb backups list / capydb backups createcapydb backups schedule get|set|disablecapydb exportcapydb export listcapydb export downloadcapydb importData-only importRestoring a Supabase dumpcapydb import follow-statuscapydb import cutovercapydb import follow-abortcapydb import preflightcapydb restorecapydb restore-points list|create|deleteMigrations from other providerscapydb migrate scancapydb migrate depscapydb migrate codemod neoncapydb migrate rlscapydb migrate verifyJobscapydb jobs getcapydb jobs listDatabase accesscapydb connection-stringcapydb psql [-- <extra psql args>]capydb seed [file.sql]capydb sql <query>capydb metricscapydb logscapydb advisor indexescapydb advisor index-hygienecapydb db lintSchema and code generationcapydb schema dumpcapydb schema diffcapydb generate types|zod|drizzle|go|pythoncapydb init drizzle|prisma|kyselyExtensionscapydb extensions list|enable|disableK/Vcapydb kv statuscapydb kv createcapydb kv credentialscapydb kv rotate-tokencapydb kv flushcapydb kv deleteAlertscapydb alerts listcapydb alerts ack <alert-id>Credentialscapydb credentials rotatecapydb roles app show|enable|rotateVersion upgradescapydb upgrade minorcapydb upgrade preflightcapydb upgrade majorcapydb upgrade confirm / capydb upgrade rollbackcapydb upgrade statusAuditcapydb audit listAPI keyscapydb api-keys list|create|revokeWebhookscapydb webhooks list|create|delete|rotate-secret|deliveriesNotificationscapydb notifications show|setMisccapydb studiocapydb integrations envcapydb integrations sync vercel|netlify|cloudflarecapydb completion bash|zsh|fish|powershellLocal files