Databases

/ infrastructure · data tier
PgBouncer 2 tenant + 3 dedicated hosts
App databases
212
one per app
Shared (Free)
151
logical DBs · tenant pool
Dedicated (Paid)
61
containers · dedicated pool
DB hosts
5
2 tenant · 3 dedicated

The data tier is a separate pool from compute workers (app data must survive restarts + gets backups), and is itself split into two host pools — so a noisy Free tenant never shares metal with a paying customer, and each side scales on its own.

Tenant DB hosts · shared Free

node class: data-tenant scale: shard new tenants
HostLogical DBs (Free)CPURAMDiskPgBouncer poolStatus
tenant-db-196
188 / 50038%
active
tenant-db-255
90 / 50018%
active

Each host runs one shared Postgres; every Free app = a logical database + role on it, injected as DATABASE_URL. Capacity is bounded by connections + storage + RAM (not container count). Free grows → add tenant-db-3 and route new tenants there (shard by host), or scale a host vertically.

Dedicated DB hosts · Paid & Custom

node class: data-dedicated 61 / 90 slots
HostContainersCPURAMDiskContainer slotsStatus
db-124
24 / 3080%
active
db-219
19 / 3063%
active
db-318
18 / 3060%
active

Each Paid/Custom app gets its own isolated Postgres container (standard versioned image, own resources + backups). They bin-pack onto hosts by slot — a host fills → add db-4. ~50–150 MB idle each, so it's a paid-tier feature.

How an app reaches its DB
app containerDATABASE_URL (injected by us)
  ↓
PgBouncer (pooling)
  ↓
Free → shared Postgres on tenant-db-1
Paid → dedicated container on db-2

safety: per-role CONNECTION LIMIT + statement_timeout
→ one app can't exhaust the pool (old FD incident)
Tier change = data migration between pools

Free → Paid: provision a container in the db-N pool, copy data (pg_dump from tenant-db-X → restore), then a brief read-only cutover repoints DATABASE_URL & redeploys. Old logical DB dropped after backup.

Paid → Free: reverse — move back into a tenant-db with room (gated: must fit the Free quota), drop the container, free the slot.

job: provisioning → copying → cutover → verifying → done | rolled_back

Dedicated databases · sample

showing 4 of 61
DatabaseApp / ownerHostTierSizeConnectionsStatus
my-app_db
JD
my-app · John Doe
db-1 Paid0.4 GB
3 / 2015%
healthy
crm-lite_db
GX
crm-lite · Globex
db-2 Custom6.2 GB
22 / 5044%
healthy
shop-api_db
AC
shop-api · Acme Inc
db-1 Custom11.8 GB
41 / 10041%
busy
portal_db
MK
portal · M. Kowalski
db-3 Paid0.9 GB
5 / 2025%
healthy