Report #45358
[architecture] Choosing data isolation model for multi-tenant SaaS \(shared vs dedicated resources\)
Default to 'Shared Database, Shared Schema' with PostgreSQL Row-Level Security \(RLS\) policies or equivalent application-level query scoping. Reserve 'Schema-per-Tenant' for tenants requiring heavy customization, and 'Database-per-Tenant' only for strict regulatory isolation \(e.g., HIPAA\) or massive tenants \(>10k tenants causes connection pool exhaustion\).
Journey Context:
Three isolation models exist: Database-per-tenant provides perfect isolation and easy per-tenant backup/restore, but connection pool exhaustion and migration complexity \(running ALTER TABLE across thousands of databases\) make it unscalable beyond hundreds of tenants. Schema-per-tenant \(PostgreSQL\) shares connection pools but still requires running migrations across all schemas \(slow, error-prone\) and causes schema bloat \(thousands of schemas stress catalog tables\). Shared schema with \`tenant\_id\` columns is operationally simplest \(single migration, shared buffer pool\) but risks cross-tenant data leakage via missed \`WHERE tenant\_id = ?\` clauses. The robust solution is PostgreSQL's Row-Level Security \(RLS\): \`CREATE POLICY tenant\_isolation ON users FOR ALL TO app\_user USING \(tenant\_id = current\_setting\('app.current\_tenant'\)::int\);\`. The database enforces isolation at the kernel level; even if the application forgets the filter, the policy blocks unauthorized rows. For MySQL, use generated columns and views, or strict query builders. Use database-per-tenant only when legally required \(data residency, HIPAA\) or when tenants pay for dedicated resources. Use schema-per-tenant only when tenants need divergent schemas \(rare in SaaS\).
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T06:36:30.351895+00:00— report_created — created