Python Multitenancy Patterns — Core Concepts

Why Multitenancy Exists

Single-tenant architecture — one deployment per customer — is the simplest model. Each customer gets their own servers, databases, and infrastructure. It’s also the most expensive. At 10 customers, it’s manageable. At 10,000, you’re maintaining 10,000 deployments, each needing updates, backups, and monitoring.

Multitenancy trades isolation simplicity for operational efficiency. One deployment, one database (or a small number), shared infrastructure. The challenge shifts to ensuring tenants don’t interfere with each other.

The Three Models

Model 1: Shared Database, Shared Schema

All tenants’ data lives in the same tables. Every table has a tenant_id column, and every query filters by it.

ProsCons
Simplest to implementOne missing WHERE tenant_id = ? leaks data
Cheapest infrastructureNoisy neighbor: one tenant’s heavy query slows everyone
Easy to aggregate across tenantsHarder to comply with data residency regulations

Best for: Early-stage SaaS with smaller customers and uniform data models.

Model 2: Shared Database, Schema Per Tenant

Each tenant gets their own database schema (namespace). Tables are identical in structure but physically separated within the same database server.

ProsCons
Stronger isolation than shared schemaSchema migrations across hundreds of schemas
Per-tenant customization possibleConnection pool management complexity
Easier data export per tenantDatabase server limits on schema count

Best for: Mid-size SaaS where tenants need some customization and stronger isolation guarantees.

Model 3: Database Per Tenant

Each tenant has a completely separate database. Maximum isolation.

ProsCons
Strongest isolationMost expensive infrastructure
Easy data residency complianceComplex routing and connection management
One bad tenant can’t affect others’ dataMigrations must run on every database
Simplest backup/restore per tenantCross-tenant analytics is very hard

Best for: Enterprise SaaS with strict compliance requirements, large tenants, or regulated industries (healthcare, finance).

Tenant Resolution

Before your app can filter data, it needs to know which tenant is making the request. Common strategies:

  • Subdomain: acme.yourapp.com → tenant is “acme”
  • Header: X-Tenant-ID: acme (common in API-first architectures)
  • Path prefix: yourapp.com/acme/dashboard
  • JWT claim: The authentication token contains the tenant ID
  • Custom domain: projects.acme.com maps to tenant “acme” via DNS

Subdomain is the most common for web apps. JWT claims are preferred for APIs.

The Noisy Neighbor Problem

When tenants share resources, one tenant’s heavy workload degrades performance for others. Solutions include:

  • Rate limiting per tenant — cap API calls, query volume, or storage
  • Resource quotas — limit CPU time, memory, or database connections per tenant
  • Queue isolation — separate background job queues per tier (premium tenants get dedicated workers)
  • Read replicas — route heavy-read tenants to dedicated replicas

Common Misconception

“We’ll start with single-tenant and add multitenancy later.” Retrofitting multitenancy onto an existing codebase is one of the hardest refactors in software engineering. Every database query, every cache key, every file path, every background job needs tenant awareness. If you know you’ll need multitenancy, design for it from the start — even if you only have one tenant initially.

One thing to remember: Choose your multitenancy model based on your isolation requirements, tenant count, and operational capacity. Shared schema is cheapest but riskiest; database-per-tenant is safest but most expensive. Most SaaS apps start with shared schema and migrate upward as compliance or scale demands it.

pythonarchitecturesaas

See Also