Connections
CapyDB speaks normal Postgres. One direct URL, one pooled URL, both usable from standard clients and frameworks.
Direct access
Use the direct URL when you need a normal PostgreSQL session: administrative SQL, psql, and migration tools that expect session-level features (advisory locks, LISTEN/NOTIFY, prepared statements with named cursors, DDL in transactions).
Pooled access
Use the pooled URL for app traffic with many short-lived connections. The infrastructure layer runs managed connection pooling (transaction pooling), so your app can stay busy without exhausting the plan's connection budget. Avoid session-level state on pooled connections - the full list of what breaks and the per-driver flags are in Connection pooling.
Which URL goes where
| Workload | URL |
|---|---|
| App runtime (web servers, serverless functions) | Pooled |
| Schema migrations (Prisma migrate, Drizzle push, Django migrate, Rails db:migrate) | Direct |
psql, GUI clients, one-off admin sessions | Direct |
pg_dump / bulk loads | Direct |
Connection fields
- Host and ports come from the project's region
- Each project has a generated database name and role name
- The dashboard exposes both URLs once the provision job completes; the CLI writes them as
DATABASE_URL,DATABASE_DIRECT_URL, andDATABASE_POOL_URL. For JavaScript/TypeScript stacksDATABASE_URLgets the pooled URL; for stacks whose canonical driver manages its own pool (pgx, SQLAlchemy, ActiveRecord, and unknown non-JS stacks) the CLI deliberately puts the direct URL inDATABASE_URLinstead - Integrations (Vercel, Netlify, GitHub Action) use the names
DATABASE_URL(pooled) andDATABASE_URL_UNPOOLED(direct) - Preview databases expose the same direct and pooled connection pattern
TLS
Connections require TLS, and issued URLs carry sslmode=verify-full. Cells are served from a publicly trusted certificate covering *.db.capydb.dev, so verify-full validates the certificate chain and the hostname - a machine-in-the-middle cannot present a substitute certificate. Keep the parameter in the URL; if a client errors with "SSL off" or refuses to negotiate TLS, check it was not stripped when the URL was copied around.
libpq-based clients need one extra parameter. psql, pgAdmin, Rails, Django and psycopg/SQLAlchemy all use libpq, which does not read your operating system's trust store by default - it looks for ~/.postgresql/root.crt and fails with root certificate file ... does not exist. Point it at the system roots:
psql "$DATABASE_URL&sslrootcert=system" # libpq 16+Drivers that use their own TLS stack - postgres.js, node-postgres, pgx, Prisma - already trust the system roots and need nothing extra. sslrootcert is consumed by libpq locally and never sent to the server, so it is safe to leave in a URL you share between tools.
Credential rotation
Rotating credentials (dashboard, POST /v1/projects/{id}/credentials/rotate) generates a new password and invalidates the old URLs. Connected Vercel and Netlify integrations re-push env vars automatically; anything else holding the old URL needs a manual update. A credentials.rotated webhook event fires when it completes. Invalidation timing and the full runbook are in Credential rotation.