As soon as an application serves more than one customer, the architecture question arrives: how do we separate tenants cleanly without making operations expensive? The answer shapes scaling, cost and compliance for years.
Three models
- Shared database, shared schema — all tenants in the same tables,
separated by
tenant_id. Cheap and simple to run, but every query must set the filter correctly. One mistake = data leak. - Shared database, separate schemas — one schema per tenant. Better isolation, moderate effort, fine into the low thousands.
- Database per tenant — maximum isolation and easy delete/export duties (GDPR), at the cost of higher operational overhead.
There is no “right” — only “right for your load, your regulation and your team”.
What actually matters
It’s not the model alone that decides, but discipline in the data layer: a central tenant context that can never be bypassed, plus tests that enforce exactly that. We usually start with shared schema and a hard tenant guard — and keep the path to stronger isolation open should a customer need it.