Database instance per tenant
Each client's relational data kept apart by the platform itself, with its own storage, compute, backups and credentials.
By: Benjamin Clark
Intent
This pattern assumes a multi-tenant platform with relational data, and tenants numbering in the tens rather than the thousands. It isolates each tenant by giving it its own private database instance. This enables two outcomes:
- A missing filter can't leak one client's data to another, because they never share a database.
- One tenant can be restored, resized or removed without affecting any other.
Motivation
A multi-tenant platform can isolate its relational data at several levels, which AWS describes as silo, pool and bridge models: shared tables with a tenant column, a schema or database per tenant on a shared instance, or an instance per tenant. The cheaper levels fail in two ways:
- Isolation depends on every query. One missing filter exposes one client's data to another.
- Tenants affect each other. One tenant's load, restore or removal can reach the others.
This pattern sits at the far end of that range: isolation comes from the platform rather than from queries. A tenant's data never shares storage, memory, credentials or backups with another's, so the guarantee holds whatever a query does. How each tenant's instance gets created is a separate concern, as in automatic client provisioning.
Applicability
Use this pattern when:
- Each tenant's relational data must be kept apart as strongly as possible, with separate storage, compute, backups and credentials.
- One tenant's load, restore or removal must never affect another's.
- Tenants number in the tens rather than the thousands, so an instance each is affordable.
Do not use this pattern when:
- You have many small tenants, where running an instance for each would cost more than the isolation is worth to them.
- Tenants' data is often queried together, where a shared store with a tenant key fits better.
Structure
Participants
| Participant | Role |
|---|---|
| Application | Serves one tenant's request, using that tenant's credentials. |
| Secrets store | Holds each instance's credentials separately. It can be any managed secrets service, such as AWS Secrets Manager. |
| Tenant's instance | Private, encrypted and TLS only, such as Amazon RDS for PostgreSQL, holding that tenant's data and nothing else. |
| Private access | The only way in for people, such as a bastion, with their own login. |
| Person | Works on one tenant's instance at a time. |
Constraints and trade-offs
- Cost grows with every tenant, because each instance runs whether it's busy or not. A database or schema per tenant on a shared instance costs far less.
- Every operation multiplies. Upgrades and maintenance happen once per tenant, and a query across tenants needs their data copied somewhere shared first.
- High availability is a business decision per environment, because a standby means another instance for every tenant.
Part of how I deliver
Where a client's contract or risk calls for the strongest separation, this is what I recommend. It's one of many patterns I bring through contract delivery, and I weigh it against the cheaper levels of isolation for your number of tenants.
Is every new client a project?
I build multi-tenant platforms where adding a client is routine, and each client's data stays its own. If you're building one, or yours has become hard to scale, book a call and we'll talk it through.
