Shared schema, schema per tenant or database per tenant?
Isolation ↔ Operational cost
Context
Pick a tenancy model before signing two enterprise customers who ask for isolation.
We're a 9-person team with ~1,200 small customers on a shared Postgres database (every table has tenant_id). Two enterprise prospects are asking for "data isolation" as a contract term.
The three classic models:
- Shared schema +
tenant_idwith row-level security - Schema per tenant in one database
- Database per tenant
Is there a sane hybrid, or are we about to run two architectures forever?
Constraints
- Tenants
- 1,200 SMB + 2 enterprise
- Team
- 9 engineers
- Stack
- Postgres, Node
Shared schema + tenant_idvsSchema per tenantvsDatabase per tenant
Community verdict
9 engineers · 5 opinions
With these constraints, what would you choose?
One choice per engineer. You can change it any time.
Ops cost →
Trade-offs
Dimensions
- Isolation
- 2Shared schema + tenant_id scores 2 of 53Schema per tenant scores 3 of 55Database per tenant scores 5 of 5
- Ops cost
- 5Shared schema + tenant_id scores 5 of 53
Community discussion
5 comments
Have you made this decision in production? Share your reasoning.
Sign in to commentAsk the enterprise prospects what "isolation" actually means to them. Often it is encryption keys per tenant and a clear deletion story, not a separate database.
The hybrid that works: one codebase, a tenant → connection lookup. Small tenants share a pooled database with RLS; enterprise tenants get their own database (same schema, same migrations) and pay for it.
The trick is that the app never knows which kind of tenant it is serving. It asks the router for a connection and runs the same queries.
And price the dedicated tier so it pays for the extra ops. Ours is a flat +$2K/month.
Turn on Postgres row-level security even if your ORM filters by tenant_id. It is the seatbelt for the day someone writes a raw query and forgets the WHERE clause.
This. RLS plus a per-request
SET app.tenant_idturned two of our pen-test findings into non-issues.