Recipes

PgDog

Postgres wire-protocol pooler — transaction mode on :6432, generated pgdog/ configs, DATABASE_URL rewrite.

Bun.SQL defaults to 10 connections per process. Scale to several app instances and N × pool can exceed Postgres max_connections. PgDog sits in front of store.sql as a transaction-pooling proxy — same wire protocol, no app code changes.

The one rule

Pin pgdog alongside store.sql and DATABASE_URL automatically points at the pooler on :6432 instead of Postgres directly — Bun.SQL and Drizzle see no difference.

Quick start

Pin both images

create-oke asks Add PgDog connection pooling…? (or pass --pgdog). Manually:

oke.config.ts
images: {
  "store.sql": "postgres:18-alpine",
  pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
},

Derive compose

oke docker

Writes ./pgdog/pgdog.toml (listen + one primary database) and ./pgdog/users.toml (same user/password/database as Postgres). The pooler waits on store-sql health before start.

Confirm the rewrite

echo "$DATABASE_URL"
# …@host:6432/db  ← pooler, not :5432
echo "$OKE_STORE_SQL_URL"   # still the direct Postgres URL when you need it

Required env

VariableRole
OKE_STORE_SQL_USER / PASSWORD / DBCopied into pgdog/users.toml for client + server auth
DATABASE_URLRewritten to the pooler URL (:6432) when PgDog is in the stack
OKE_PGDOG_URLSame value as pooled DATABASE_URL when both are present
OKE_STORE_SQL_URLDirect Postgres host — bypass the pooler for admin / migrations

PgDog itself has no separate credential env — it mounts the generated TOML files read-only.

Data and backup

MountWhat it is
./pgdog/pgdog.toml:/pgdog/pgdog.toml:roGenerated listen + [[databases]] (host store-sql, port 5432)
./pgdog/users.toml:/pgdog/users.toml:roGenerated [[users]] credentials

No database state lives in the PgDog container. Backing up PgDog means keeping those two config files (they are regenerated by oke docker). Durable data stays on the Postgres volume / dump.

Production note

Pooling mode is transaction — set explicitly (also PgDog's upstream default). Naive poolers can leak session state (SET, RLS vars, LISTEN/NOTIFY) across clients; PgDog re-applies that state per transaction.

Do not stack PgDog in front of a managed pooler (Neon -pooler, Supabase Supavisor :6543). Pick one pooler. Use OKE_STORE_SQL_URL (direct) for migrations and anything that needs session features.

Read-replica routing (BEGIN READ ONLY → replica) is documented readiness in PgDog — not wired into the generated stack yet.

What the recipe configures

FieldValue
Container port6432
dependsOnstore-sql healthy
Healthcheckpg_isready -h 127.0.0.1 -p 6432, every 2s, 20 retries
Connection URLpostgres://user:pass@host:6432/db

Troubleshooting

Learn more

Next

On this page