Performance

Multi-Tenant SaaS: Three Data Isolation Patterns Compared

Database-per-tenant, schema-per-tenant, and shared schema with row-level security — the trade-offs, when to use each, and PostgreSQL RLS implementation.

admin · March 13, 2026 · 2 min read

Pattern 1: Database per Tenant

Maximum isolation — each tenant has a physically separate database. A bug that exposes one tenant’s data cannot reach another’s. Appropriate for enterprise contracts with strict data residency requirements or highly regulated data. Cost scales linearly with customer count, making it impractical for self-serve SaaS products with many smaller customers.

Pattern 2: Schema per Tenant (Our B2B SaaS Default)

Each tenant gets their own PostgreSQL schema within a shared database. The application sets search_path to the tenant’s schema on each connection. Strong isolation — SQL injection in tenant A’s context cannot read tenant B’s tables without explicit cross-schema references. One database to back up, monitor, and scale. Manageable migrations with Flyway and Liquibase’s schema-per-tenant support.

Pattern 3: Shared Schema with Row-Level Security

All tenants share the same tables. Every table has a tenant_id column. PostgreSQL row-level security enforces that queries return only rows matching the current session’s tenant_id — at the database level, not the application level. Simplest to operate and most appropriate for consumer SaaS or B2B products with many small customers.

Our Recommendation

Schema-per-tenant for B2B SaaS with 10–10,000 business customers. Shared schema with RLS for consumer products. Database-per-tenant for enterprise contracts with strict compliance or data residency requirements.