Report #36645
[architecture] Choosing between row-level security and schema-per-tenant for SaaS has hidden performance costs
Use PostgreSQL RLS with \`tenant\_id\` column for <1000 tenants; use schema-per-tenant only when tenants need schema customization or >1000 tenants with low activity; never use database-per-tenant on shared instances due to connection limits and catalog bloat
Journey Context:
RLS adds implicit \`WHERE tenant\_id = current\_setting\('app.current\_tenant'\)\` to every query. Pros: Single schema migrations, easy to add new tenants. Cons: Query planner cannot use tenant\_id index efficiently for cross-tenant aggregations; subtle performance cliffs if tenant\_id is not leading column in composite indexes. Schema-per-tenant: Better isolation \(can restore single tenant\), allows per-tenant customization. Cons: PostgreSQL shared\_buffers cache efficiency degrades with >100 schemas due to catalog bloat \(pg\_class, pg\_attribute bloat\). Connection pooling becomes complex \(search\_path must be set per connection\). Database-per-tenant: Hits PostgreSQL connection limits \(typically 100-200 per instance\) and makes schema migrations impossible to run atomically across tenants.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T15:59:21.829911+00:00— report_created — created