Database

Create and manage Postgres databases with ccp db.

Database

Cluster provides managed Postgres databases running in Firecracker microVMs. Each database gets its own isolated VM with a SQL-over-HTTP proxy for secure access.

Create a Database

ccp db create --name my-app-db
# ✓ Created database my-app-db
#
#   ID    db-c1cf9a9be667
#   Host  db-c1cf9a9be667.clusterbase.dev
#   Token a9db7b185e40...
#
# ✓ Token saved to .cluster/config.json

If you run this from a project directory with a .cluster/config.json, the database credentials (DATABASE_URL and DATABASE_TOKEN) are automatically injected as environment variables into your linked function.

List Databases

ccp db list
# • my-app-db  ready  db-c1cf9a9be667
#   db-c1cf9a9be667.clusterbase.dev

Show Database Details

ccp db info db-c1cf9a9be667
# Database my-app-db
#
#   ID       db-c1cf9a9be667
#   Status   ready
#   Host     db-c1cf9a9be667.clusterbase.dev
#   Database default
#   User     clusterbase

Delete a Database

ccp db destroy db-c1cf9a9be667
# Delete database db-c1cf9a9be667? This will destroy all data. (y/N)

Use -y to skip the confirmation prompt.

Interactive SQL Shell

Open an interactive SQL session with ccp db connect:

ccp db connect

This opens a terminal UI with a SQL prompt. Type queries ending with ; to execute them:

  ╭──────────────────────────────────────────────────╮
  │ >_ ccp db connect (db-c1cf9a9be667)              │
  │                                                   │
  │ database:  default                                │
  │ host:      db-c1cf9a9be667.clusterbase.dev        │
  ╰──────────────────────────────────────────────────╯

  › SELECT * FROM users;

  id │ name  │ email
  ───┼───────┼──────────────
  1  │ Alice │ alice@co.com

  (1 row)

  43ms

  › Enter SQL (end with ;)

Meta-commands

CommandDescription
\dtList all tables
\d <table>Describe a table (columns, types)
\qQuit
  • Up/Down arrows — cycle through query history
  • Ctrl+D or Ctrl+C — exit (clears input if non-empty)

One-Shot SQL

Execute a single SQL statement without opening the interactive shell:

ccp db exec "SELECT count(*) FROM users;"
#
#   count
#   ─────
#   42
#
#   (1 row)
#
#   38ms

Works for any SQL — SELECT, INSERT, UPDATE, DELETE:

ccp db exec "INSERT INTO users (name, email) VALUES ('Bob', 'bob@co.com');"
#
#   1 row affected · 45ms

Statements with RETURNING clauses display the returned rows:

ccp db exec "DELETE FROM users WHERE id = 1 RETURNING *;"

Migrations

Run SQL migration files against your database with ccp db migrate. Migrations are tracked in a _ccp_migrations table so they only run once.

Setup

Create a migrations/ directory in your project with numbered .sql files:

migrations/
  001_create_users.sql
  002_add_posts.sql
  003_add_indexes.sql

Each file can contain multiple SQL statements. PL/pgSQL functions with $$ dollar-quoting are fully supported.

Run Migrations

ccp db migrate
# › Running 3 pending migrations...
#
# ✓ 001_create_users.sql  48ms
# ✓ 002_add_posts.sql     37ms
# ✓ 003_add_indexes.sql   42ms
#
# ✓ 3 migrations applied

Running again is safe — only pending migrations are applied:

ccp db migrate
# ✓ All 3 migrations already applied

Check Status

See which migrations have been applied without running anything:

ccp db migrate --status
# › Migration status:
#
# ✓ 001_create_users.sql
# ✓ 002_add_posts.sql
# ○ 003_add_indexes.sql
#
# 1 pending migration

Options

FlagDescription
--dir <PATH>Migrations directory (default: ./migrations)
--db-id <ID>Database ID (reads from .cluster/config.json if omitted)
--token <TOKEN>Database token (reads from .cluster/config.json if omitted)
--statusShow migration status without applying

If you provide --db-id, you must also provide --token (and vice versa).

How It Works

Each migration runs in a database transaction. The migration SQL and the tracking insert are atomic — if the migration fails, nothing is committed. Migrations are applied in filename order, so use a numeric prefix (001_, 002_, etc.) to control the sequence.

Backups

Databases are backed up automatically once per day and backups are retained for 7 days. You can also create manual backups on demand.

Create a Backup

ccp db backup create
# ✓ Backup created
#   ID         bkp-8f3e2a1c
#   Created   2026-04-12 14:22 UTC

Use --db-id <ID> to target a database other than the one in your .cluster/config.json.

List Backups

ccp db backup list
# • bkp-8f3e2a1c  manual     2026-04-12 14:22 UTC
# • bkp-7d1f9e4b  scheduled  2026-04-11 00:00 UTC
# • bkp-6c9a2d7e  scheduled  2026-04-10 00:00 UTC

ls is an alias for list.

Restore from a Backup

ccp db backup restore bkp-8f3e2a1c
# Restore database db-c1cf9a9be667 from bkp-8f3e2a1c? This will overwrite current data. (y/N)

Use -y / --yes to skip the confirmation prompt.

Delete a Backup

ccp db backup delete bkp-8f3e2a1c

rm is an alias for delete.

Querying from Handlers

Access your database from serverless functions using the SQL-over-HTTP proxy:

const res = await fetch(`https://${process.env.DATABASE_ID}.clusterbase.dev/query`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${process.env.DATABASE_TOKEN}`,
  },
  body: JSON.stringify({
    sql: "SELECT * FROM users WHERE id = $1",
    params: [42],
  }),
});

const { rows } = await res.json();

Endpoints

EndpointMethodDescription
/queryPOSTExecute a SELECT query, returns { rows, fields }
/executePOSTExecute INSERT/UPDATE/DELETE, returns { rows_affected }
/transactionPOSTExecute multiple statements atomically

Request Format

{
  "sql": "SELECT * FROM users WHERE id = $1",
  "params": [42]
}

Parameters use $1, $2, etc. for positional binding.

Transaction Format

{
  "statements": [
    { "sql": "INSERT INTO users (name) VALUES ($1)", "params": ["Alice"] },
    { "sql": "INSERT INTO logs (action) VALUES ($1)", "params": ["user_created"] }
  ]
}

Aliases

CommandAlias
ccp db listccp db ls
ccp db destroyccp db rm

On this page