Skip to content

18 — Multi-Tenant Systems

Multi-tenancy means a single instance of software serves multiple customers (tenants). Each tenant’s data is isolated from others, but they share the same infrastructure.

Analogy: Multi-tenancy is like an apartment building. The building (system) has shared infrastructure — elevators, lobby, utilities — but each apartment (tenant) is private and separate. Tenants have keys to their own apartment, not their neighbors’.


Building multi-tenant systems is hard because:

  • Data isolation — one tenant must never see another tenant’s data
  • Noisy neighbors — one tenant’s heavy usage degrades service for others
  • Configuration per tenant — features, limits, branding differ per tenant
  • Scaling — how do you scale when tenants grow unevenly?
  • Cost attribution — who’s using how many resources?

flowchart TB
Isolation["Tenant Isolation Models"] --> Silo["Silo (Single-Tenant DB)<br/>Each tenant has own DB<br/>Strong isolation"]
Isolation --> Pool["Pool (Shared DB)<br/>All tenants share DB<br/>Tenant_id on every row"]
Isolation --> Hybrid["Hybrid<br/>Silo for large tenants<br/>Pool for small tenants"]
Silo --> SiloPros["✅ Best isolation<br/>✅ Easy restore<br/>❌ Highest cost"]
Pool --> PoolPros["✅ Lowest cost<br/>✅ Easy to add tenants<br/>❌ Complex queries"]
Hybrid --> HybridPros["✅ Best of both<br/>❌ Complex management"]
style Isolation fill:#7c3aed,color:#fff
style Silo fill:#3b82f6,color:#fff
style Pool fill:#059669,color:#fff
style Hybrid fill:#f59e0b,color:#fff
ModelIsolationCostComplexityBest For
Silo (per-tenant DB)StrongestHighestLowEnterprise, compliance-heavy
Pool (shared DB)Moderate (row-level)LowestMediumSmall tenants, low-cost SaaS
Hybrid (silo + pool)ConfigurableMediumHighSaaS with mixed tenant sizes
Schema per tenantStrong (schema-level)MediumMediumRegional or vertical SaaS

sequenceDiagram
participant UserA as Tenant A User
participant UserB as Tenant B User
participant App as Application
participant DB as Database
UserA->>App: List my orders
Note over App: Tenant A identified from auth token
App->>DB: SELECT * FROM orders WHERE tenant_id = 'A'
DB-->>App: [Orders for Tenant A only]
App-->>UserA: Your orders ✅
UserB->>App: List my orders
Note over App: Tenant B identified
App->>DB: SELECT * FROM orders WHERE tenant_id = 'B'
DB-->>App: [Orders for Tenant B only]
App-->>UserB: Your orders ✅
Note over App,DB: Tenant A cannot see Tenant B's data

When one tenant consumes more resources than expected, impacting others:

flowchart TB
subgraph Normal["Normal Operation"]
T1["Tenant A: 100 req/s"] --> Shared["Shared Resources"]
T2["Tenant B: 50 req/s"] --> Shared
T3["Tenant C: 30 req/s"] --> Shared
Shared -->|"180 req/s total"| OK["✅ All tenants happy"]
end
subgraph Noisy["Noisy Neighbor Scenario"]
T1_BAD["Tenant A: 10,000 req/s 💥"] --> Shared2["Shared Resources<br/>🔥 Overloaded"]
T2_BAD["Tenant B: 50 req/s"] --> Shared2
T3_BAD["Tenant C: 30 req/s"] --> Shared2
Shared2 -->|"Timeout/Latency"| BAD["❌ Tenant B & C suffer"]
end
style Normal fill:#059669,color:#fff
style Noisy fill:#ef4444,color:#fff

Solutions:

SolutionHow It Works
Rate limiting per tenantEach tenant has a max request limit
Resource quotasCPU/memory limits per tenant (container cgroups)
Provisioned capacityEach tenant gets a guaranteed minimum
Auto-isolationMove noisy tenants to isolated resources

flowchart TB
subgraph TenantLayer["Tenant Layer"]
T1["Tenant 1<br/>Auth + Config"]
T2["Tenant 2<br/>Auth + Config"]
T3["Tenant 3<br/>Auth + Config"]
end
subgraph SharedLayer["Shared Application Layer"]
API["API Gateway"]
Auth["Auth Service"]
Rate["Rate Limiter<br/>(per tenant)"]
end
subgraph DataLayer["Data Layer"]
DB1["DB: Tenant 1 (Silo)"]
DB2["DB: Tenant 2 (Silo)"]
PoolDB["Shared DB: Tenants 3-N<br/>(Pooled)"]
end
T1 & T2 & T3 --> API
API --> Auth --> Rate
Rate --> DB1 & DB2 & PoolDB
style TenantLayer fill:#3b82f6,color:#fff
style SharedLayer fill:#7c3aed,color:#fff
style DataLayer fill:#059669,color:#fff

StrategyHow It WorksWhen to Use
Row-level tenant_idSingle DB, all rows have tenant_idSimple multi-tenant apps
Schema per tenantSame DB, separate schema per tenantRegional SaaS, moderate isolation
Database per tenantSeparate DB per tenantEnterprise, compliance, large tenants
Sharded per tenant groupGroup tenants into shardsScaling pool model at high volume

Configuration TypeExamplesStorage
Feature flagsEnable/disable features per tenantDatabase or config service
Rate limitsAPI rate limits, concurrency capsPer-tenant config in DB
Custom brandingLogo, colors, domain per tenantConfig file or DB
Integration settingsAPI keys, webhook URLs per tenantEncrypted DB columns
Billing planTier limits, pricing per tenantBilling service

DecisionProsCons
Pool (shared DB)Lowest cost, easy tenant creationComplex queries, row leaks risk
Silo (per-tenant DB)Strong isolation, easy restoreHigher cost, harder migrations
Per-tenant rate limitsFair resource distributionConfiguration overhead
No per-tenant limitsSimple to implementNoisy neighbor problem

StrategyDescription
Auto-isolationAuto-move high-usage tenants to dedicated resources
Hierarchical rate limitingPer-tenant cap + account-level cap
Read replicas per tenantIsolate read traffic for large tenants
Shard by tenant groupGroup tenants into clusters of N tenants each
Caching per tenantSeparate cache keys/namespaces per tenant

  1. What are the pros and cons of silo vs pool multi-tenant architecture?
  2. How do you prevent one tenant from accessing another tenant’s data?
  3. How would you handle a “noisy neighbor” that’s degrading service for others?
  4. How do you implement per-tenant configuration and feature flags?
  5. When would you choose a hybrid multi-tenant approach?

SystemMulti-Tenant Approach
SalesforceHybrid — pool for small orgs, silo for enterprise
SlackPool with strong row-level isolation
ShopifyPer-tenant database (silo) — each store is separate
AWSAccounts are natural silos — each AWS account = one tenant

  • Multi-tenancy = one system serving multiple customers with data isolation
  • Silo (per-tenant DB) = strongest isolation, highest cost — best for enterprise
  • Pool (shared DB) = lowest cost, moderate isolation — best for small tenants
  • Hybrid = silo for big tenants, pool for small — best for mixed customer sizes
  • Noisy neighbor = one tenant using too many resources — fix with rate limits or isolation
  • Always include tenant_id in every query — a missing filter is a data leak
  • Choose isolation level based on compliance needs, tenant size, and cost constraints