example

December 10, 2025 Β· admin
TL;DR: Choosing between database-per-tenant and shared-schema is trade-off heavy. Use DB-per-tenant when isolation, per-tenant backups, and tenant-level scaling matter. Use shared-schema when you need operational simplicity and lower cost for many small tenants.

Practical comparison: database-per-tenant vs shared-schema (what to pick and why)

Published: Β· Asad Ali

Long-form technical posts can be a lot. Below I break this topic into small, actionable pieces with war stories, a checklist, and a final scorecard so you can decide quickly.


Quick scenario β€” context before choices

Imagine you’re building a SaaS that will start with a handful of customers but aims to serve thousands in 2 years. Some customers will have strict data isolation requirements (finance, healthcare), others will be tiny free-tier tenants. How do you design the data layer?

Real snapshot: in one billing system we shipped with shared-schema to move fast. During month-end, a single tenant’s heavy queries slowed the entire platform β€” costing us an emergency weekend patch. Isolation would have avoided that outage.

This is where most systems break in production.

What “DB-per-tenant” actually buys you

  • Isolation: noisy neighbor problems are physical β€” each DB is separate.
  • Tailored ops: per-tenant backups, restores, and scaling.
  • Security: easier to satisfy strict compliance for specific tenants.
Tip: DB-per-tenant is not a switch you throw on for every tenant. Use it for a subset (big/key customers) while keeping smaller tenants on shared schema.

What “Shared-schema” actually buys you

  • Lower cost: fewer database instances to manage.
  • Simpler deployment: single migration, single schema versioning flow.
  • Easier analytics: cross-tenant queries are trivial.
Debug hint: When using shared-schema, ensure tenant-id filtering exists on every query path. Missing WHERE clauses are the most common production bug.

What NOT to do (short anti-pattern list)

Anti-pattern: Start with DB-per-tenant for everyone to β€œbe safe.” You’ll pay operational debt immediately (backups, patching, monitoring). Only convert specific tenants when needed.

Micro-punchline

Choose per-tenant for isolation; choose shared-schema for speed of development and cost. Nothing magical β€” just trade-offs.

Implementation considerations (practical checklist)

  • β˜‘ Tenant identification: How does your app resolve tenant context? (subdomain, header, token claim)
  • β˜‘ Migrations: Can you run safe zero-downtime migrations across many DBs?
  • β˜‘ Backups & restores: Can you restore a single tenant quickly?
  • β˜‘ Monitoring & cost: Do you have alerts per database? Cost per tenant tracked?
Best practice: Instrument cost-per-tenant early. If a tenant consumes >X% of resources, consider moving them to a dedicated DB.

Code patterns β€” sample switch (C#)

Simple factory that returns a connection string based on tenant id (very simplified):

 // resolve tenant id from request context string tenantId = TenantContext.Current.Id; // pick strategy if (TenantRegistry.IsDedicated(tenantId)) { connectionString = TenantRegistry.GetDedicatedConnection(tenantId); } else { connectionString = SharedDatabase.ConnectionString; } // use DbContextOptionsBuilder with that connection string var options = new DbContextOptionsBuilder<AppDbContext>() .UseSqlServer(connectionString) .Options; 
Note: Avoid changing the DbContext type at runtime. Prefer configuring connection string per context instance, not swapping types.

Migration strategies

With DB-per-tenant you must run migrations on N databases. Options:

  1. Central orchestration: a service that attempts to apply migrations sequentially or in parallel with backoff.
  2. Blue-green DBs: create a new DB, warm it, then cut over (complex but safer).
  3. Feature flags + tenant grouping: gradually migrate tenants and roll back if issues occur.
Warning: Running schema-altering migrations concurrently across many DBs without proper backouts can be catastrophic.

Performance tips

  • Index per tenant if patterns differ per tenant.
  • Use read-replicas for heavy-read tenants (DB-per-tenant enables per-tenant replicas).
  • Consider caching layers (Redis) with tenant-scoped keys: cache:{tenantId}:user:123.

Short war story

In 2020, we had a tenant run an ad-hoc reporting query that scanned the entire orders table β€” shared schema β€” and it amplified to an 8x CPU spike across the cluster. We switched that tenant to a separate read-replica and added query cost quotas. It saved the platform.

Mini checklist β€” when to choose DB-per-tenant

  • β˜‘ Tenant requires strict compliance or physical separation
  • β˜‘ Tenant’s workload is large and unpredictable
  • β˜‘ You need per-tenant backup/restore

Mini checklist β€” when to choose shared-schema

  • β˜‘ Most tenants are small and homogeneous
  • β˜‘ You want fast onboarding and low infra cost
  • β˜‘ Cross-tenant analytics are important

What to monitor (operational)

  • Per-tenant DB CPU and I/O
  • Slow query trends per tenant
  • Cost per tenant (broken down daily)
  • Number of connections per tenant

See also

I covered safe EF Core migrations and connection pooling in previous posts β€” worth a quick read if you’re implementing multi-tenant DBs.

β€œGood architecture is not about making perfect choices. It’s about managing trade-offs wisely.”

β€” Unknown Architect

Final scorecard (quick comparison)

Factor DB-per-tenant Shared-schema
Isolation ⭐⭐⭐⭐⭐ ⭐⭐⭐
Complexity ⭐⭐ ⭐⭐⭐⭐
Scale ⭐⭐⭐⭐⭐ ⭐⭐⭐
Cost ⭐⭐ ⭐⭐⭐⭐

Closing thoughts

There is no one-size-fits-all. Start with the simplest approach that meets SLAs and be prepared to carve out specific tenants to dedicated infrastructure as they grow. The operational burden is real β€” plan migrations, monitoring, and cost-tracking ahead of time.

Final takeaway: design for migration. If moving a tenant from shared-schema to dedicated DB is impossible, you built a system that will fight you later.

Actionable next steps (3-minute checklist)

  1. Instrument per-tenant metrics now (CPU, I/O, requests).
  2. Create a migration playbook for moving a tenant to a dedicated DB.
  3. Add a query-cost watchdog to detect expensive ad-hoc reports.
Get similar architecture notes in your inbox
Practical patterns, war stories, and runnable code β€” once a week.
No spam. Unsubscribe any time.

Enjoyed this? If you want I can convert this into a multi-part series with diagrams and per-tenant migration scripts.