Designing multi-tenant Postgres without regrets
Pool, schema-per-tenant, or row-level security? A short guide to the tradeoffs and what we usually recommend.
Three real options
1. Pool (shared schema)
One database, one schema, a tenant_id on every table. Simple to operate, harder to isolate. Default choice for <1k tenants and homogeneous data.
2. Schema-per-tenant
One database, many schemas. Clean isolation, painful migrations, breaks under thousands of tenants.
3. Row-level security (RLS)
Pool-style data with Postgres-enforced isolation policies. Powerful, requires discipline, and forces you to keep set_config('app.tenant', ...) bulletproof.
What we ship most often
Pool + RLS, with explicit per-query tenant context, audit logs, and a kill switch for cross-tenant queries in non-admin paths. It scales to thousands of tenants comfortably and gives you isolation guarantees you can show an auditor.
