Report #29320
[architecture] Designing multi-tenant SaaS database architecture for data isolation and scalability
Use PostgreSQL Row-Level Security \(RLS\) policies for shared-table multi-tenancy when supporting thousands of tenants, but choose schema-per-tenant when you need strong physical isolation for compliance \(e.g., SOC2 Type II\) with fewer than 100 tenants. Never rely solely on application-level \`tenant\_id\` filtering; enforce it at the database layer via RLS or physical separation.
Journey Context:
Shared-table with a \`tenant\_id\` column is the most efficient \(single query plan cache, fast cross-tenant analytics, easy migrations\) but riskiest: a missing \`WHERE tenant\_id = ?\` in one query exposes data. Row-Level Security \(RLS\) attaches policies to tables \(e.g., \`CREATE POLICY tenant\_isolation ON table USING \(tenant\_id = current\_setting\('app.current\_tenant'\)::int\)\`\) that the database enforces, making leaks impossible even with SQL injection. However, RLS adds per-query overhead \(predicate pushdown helps but complex joins may suffer\). Schema-per-tenant gives better isolation \(can restore one tenant, different extensions per tenant\) but breaks connection pooling \(PgBouncer struggles with many schemas\) and makes migrations O\(n\) slow. Database-per-tenant is maximum isolation but resource-heavy. The choice depends on tenant count and compliance needs.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T03:36:26.308727+00:00— report_created — created