CapyDB Docs
Getting StartedConnect your framework

Node: pg and postgres.js

Plain Node Postgres drivers against CapyDB, no ORM required.

Environment

.env
DATABASE_URL="postgres://user:password@host:6432/db?sslmode=require"
DATABASE_DIRECT_URL="postgres://user:password@host:5432/db?sslmode=require"

node-postgres (pg)

import pg from 'pg'

const pool = new pg.Pool({
  connectionString: process.env.DATABASE_URL,
  max: 10,
})

const { rows } = await pool.query('SELECT now()')

A pg.Pool on top of the pooled URL is fine — the client-side pool keeps connections warm per process, the server-side pooler multiplexes across processes. Keep max modest; the plan's connection budget is shared by everything you run.

postgres.js

import postgres from 'postgres'

const sql = postgres(process.env.DATABASE_URL!, { prepare: false })

const rows = await sql`SELECT now()`

prepare: false is required on the pooled URL; named prepared statements do not survive transaction pooling. On the direct URL you can leave it on.

Long-lived workers

A worker that holds one steady connection (queue consumer, cron process) can use the direct URL — that is what it is for. Just count those connections against the plan budget (15/30/60 for Vibe/Ship/Business).

Pitfalls

  • SSL connection required: keep sslmode=require in the URL.
  • too many connections: lower the client pool max, move app traffic to the pooled URL, or check Observability for what is holding connections.
  • LISTEN/NOTIFY and session state do not work through the transaction pooler — use the direct URL for those.