Multi-Tenant Data Isolation Patterns
When you're building a SaaS product, one of the earliest architectural decisions is how to isolate tenant data. Get it wrong and you'll be doing a painful migration later. Get it right and you'll scale smoothly for years.
We've tried all three patterns at Zonda. Here's what we learned.
Pattern 1: Shared Collection, Tenant ID Field
The simplest approach. Every document has a tenantId field, and every query filters by it.
db.orders.find({ tenantId: "acme-corp", status: "pending" })
Pros: Simple, cost-effective, easy to manage indexes.
Cons: One bad query without a tenant filter can leak data across tenants. Noisy neighbor problems if one tenant has 100× more data.
Pattern 2: Database-Per-Tenant
Each tenant gets their own MongoDB database. The application resolves the connection at request time based on the authenticated tenant.
Pros: Strong isolation, easy per-tenant backups and restores, no accidental cross-tenant queries.
Cons: Connection pool management becomes complex. Schema migrations need to run across all tenant databases.
Pattern 3: Cluster-Per-Tenant
For enterprise customers with strict compliance requirements, we provision dedicated clusters.
Pros: Complete isolation, independent scaling, meets the strictest compliance requirements.
Cons: Expensive, operationally complex, long provisioning times.
What We Actually Do
A hybrid approach:
- Free and starter tiers → shared collection with tenant ID
- Business tier → database-per-tenant on shared clusters
- Enterprise tier → dedicated clusters
The routing layer in our application middleware handles this transparently. The business logic doesn't know or care which isolation pattern is in use.
Start with the simplest isolation pattern that meets your compliance requirements. You can always upgrade a tenant's isolation level — downgrading is nearly impossible.