Multi-tenancy is essential for SaaS applications, but choosing the right architecture can be tricky. Let's explore the three main patterns and when to use each.
Pattern 1: Shared Database, Shared Schema
All tenants share the same tables with a tenant_id column.
Pros:
- Simple to implement
- Efficient resource usage
- Easy cross-tenant analytics
Cons:
- Risk of data leaks if RLS fails
- Performance can degrade at scale
- Harder to backup individual tenants
Implementation with Supabase RLS
-- Enable RLS
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
-- Policy for tenant isolation
CREATE POLICY tenant_isolation ON documents
USING (tenant_id = auth.jwt() ->> 'tenant_id');
Pattern 2: Shared Database, Separate Schemas
Each tenant gets their own PostgreSQL schema.
Pros:
- Stronger isolation
- Easy per-tenant backups
- Better for regulated industries
Cons:
- Schema migrations are complex
- More database connections needed
- Harder to query across tenants
Implementation
# Dynamic schema selection
def get_tenant_schema(tenant_id: str) -> str:
return f"tenant_{tenant_id}"
# Use in queries
engine = create_engine(
DATABASE_URL,
execution_options={"schema_translate_map": {None: get_tenant_schema(tenant_id)}}
)
Pattern 3: Database per Tenant
Each tenant has their own database instance.
Pros:
- Maximum isolation
- Independent scaling
- Easiest compliance
Cons:
- Most expensive
- Complex infrastructure
- Difficult to manage at scale
Which Pattern Should You Use?
Choose Pattern 1 (shared schema) if:
- You're a startup with < 1000 tenants
- Data sensitivity is low to medium
- You need fast development velocity
Choose Pattern 2 (separate schemas) if:
- You have compliance requirements
- Tenants have varying data volumes
- You need per-tenant backups
Choose Pattern 3 (separate databases) if:
- You serve enterprise customers
- Data must never be co-located
- Tenants need custom SLAs
Shipfastai's Approach
We use Pattern 1 by default with Supabase RLS, but our Enterprise tier includes Pattern 2 support. This gives you the best of both worlds: fast development for most customers and stronger isolation when needed.