Report #51045
[architecture] Selecting isolation strategy for multi-tenant SaaS data \(row-level vs schema-per-tenant vs database-per-tenant\)
Start with Row-Level Security \(RLS\) or \`tenant\_id\` discriminator columns with composite indexes \`\(tenant\_id, id\)\` for cost efficiency and operational simplicity. Migrate to schema-per-tenant only when strict compliance \(SOC2/HIPAA\) requires physical isolation or noisy-neighbor protection at the connection pool level. Avoid database-per-tenant unless serving enterprise tiers with dedicated SLAs due to connection pool exhaustion and migration complexity.
Journey Context:
The naive approach of database-per-tenant scales poorly because connection pools are exhausted \(Postgres default 100 connections, quickly consumed by connection pooling middleware\). Schema-per-tenant \(Postgres\) shares resources but complicates migrations \(dynamic search\_path or schema-qualified queries break ORM assumptions\) and fails to isolate CPU/memory \(noisy neighbor\). Row-Level Security with \`tenant\_id\` is most efficient but requires strict application discipline: every query must include the tenant predicate, and sequences must be non-shared to prevent information leakage via timing attacks \(inferring tenant existence via sequence gaps\). The specific mistake of using shared sequences with RLS is a critical security flaw often missed. The migration path from RLS to schema-per-tenant is painful \(data export/import\), so the choice must anticipate compliance needs early.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T16:09:47.843698+00:00— report_created — created