The Cost of Getting It Wrong
We built a SaaS in 2019. Single-tenant.
Each customer got their own database.
Fine at 10 customers. Nightmare at 100.
Here's what we learned.
The Multi-Tenant Options
1. Shared Database, Shared Schema
All customers in one database. One schema.
Filter by tenant_id everywhere.
Pros: Simple, cheap Cons: Data isolation harder, backup complexity
2. Shared Database, Separate Schemas
PostgreSQL schemas per tenant.
Pros: Better isolation, easier backup Cons: Schema migrations complex
3. Separate Databases (Don't Do This)
One database per customer.
Pros: Strong isolation Cons: Operationally nightmare at scale
What We Recommend
For most SaaS: Shared database, tenant_id filter.
Simple. Works. Scales to millions of rows.
The Implementation
1. Add tenant_id to Every Table
CREATE TABLE users (
id UUID PRIMARY KEY,
tenant_id UUID NOT NULL,
email TEXT NOT NULL,
...
);
2. Set It Globally
In Supabase/Postgres, set default tenant context.
3. Filter Everywhere
RLS policies enforce tenant isolation.
The Mistakes We Made
1. Forgot to Filter Cron Jobs
Backend jobs ran as admin. Data leaked.
Fix: Always run jobs in tenant context.
2. Missing Indexes
Tenant queries were slow.
Fix: Index tenant_id on every table.
3. No Tenant Cleanup
Orphaned data everywhere.
Fix: Cascade deletes on tenant deletion.
The Checklist
- tenant_id on every table
- RLS policies enabled
- Indexes on tenant_id
- Cron jobs run in tenant context
- Backup strategy for tenant data
- Tenant deletion cascade
The Honest Answer
Multi-tenancy isn't hard. It's tedious.
Do it right from day one. Retrofit is painful.