Capabilities/SaaS Platform

Multi-Tenant Architecture

Shared infrastructure with tenant isolation, noisy neighbor protection, and per-tenant customization

multi-tenantSaaSisolationdatabasescaling

Learning lens

Start with judgment, not a universal prescription.

This page is a learning model for understanding the capability. It does not claim exact production internals, exact costs, or an infinite-scale architecture.

Evidence

Conceptual pattern

0->1 default

Start with clear tenant boundaries, boring data ownership, and reversible choices before optimizing for platform scale.

Cost drivers

tenant isolationcustom configurationbackground jobssupport tooling

Watch for breakpoints

  • -large tenants affect small tenants
  • -support teams need self-serve controls
  • -migration work becomes tenant-specific

Learn first

Concepts behind this architecture

The Problem

SaaS applications serve multiple customers (tenants) from shared infrastructure. The challenge is balancing cost efficiency (shared resources) with isolation (one tenant’s data, load, or failures shouldn’t affect others). Multi-tenancy touches every layer — database, compute, caching, queues, and storage. You must decide how much isolation each tier of customer gets, how to route requests to the right tenant context, and how to handle tenants that outgrow the shared model.

Architectural Approaches

Shared Database, Shared Schema

All tenants share the same database and tables. A tenant_id column on every table discriminates data. Application code adds WHERE tenant_id = ? to every query. Simplest and most cost-effective approach, used by most early-stage SaaS.

Pros

  • +Lowest infrastructure cost — one database for all tenants
  • +Simplest to deploy and manage
  • +Easy cross-tenant analytics and reporting
  • +Database migrations apply to all tenants at once

Cons

  • −Risk of data leaks if tenant_id filter is missed (security critical)
  • −Noisy neighbor — one tenant's heavy query affects all others
  • −Hard to meet data residency requirements per tenant
  • −Schema customization per tenant is difficult

Shared Database, Separate Schemas

Each tenant gets their own database schema (PostgreSQL schemas, MySQL databases) within a shared database server. Provides logical isolation while sharing compute resources. Tenant routing happens at the connection/schema level.

Pros

  • +Logical data isolation — harder to accidentally leak data
  • +Per-tenant schema customization is possible
  • +Can use database-level access controls per schema
  • +Easier to export/delete a single tenant's data (GDPR)

Cons

  • −Schema migrations must run per-tenant — can be slow with many tenants
  • −Connection pooling is more complex (pool per schema or dynamic switching)
  • −Still shares compute — noisy neighbor at the DB server level
  • −Operational overhead grows with tenant count

Database per Tenant

Each tenant gets a completely separate database instance. Maximum isolation at maximum cost. Reserved for enterprise tiers, regulated industries, or tenants with data residency requirements.

Pros

  • +Complete data isolation — strongest security boundary
  • +Per-tenant performance tuning and scaling
  • +Easy to meet data residency (place DB in specific region)
  • +Tenant migration and backup/restore is straightforward

Cons

  • −Highest infrastructure cost
  • −Operational complexity grows linearly with tenants
  • −Cross-tenant queries and analytics require federation
  • −Connection management across hundreds of databases is challenging

Architecture

Loading diagram...
Multi-Tenant Architecture — High-level architecture

Key Components

Tenant Router Middleware

Extracts tenant context from the request (subdomain, custom domain, JWT claim, or API key). Sets tenant_id in the request context so all downstream code operates in the correct tenant scope. This is the most security-critical component — a bug here causes cross-tenant data leaks.

Tenant-Aware Data Layer

Wraps database queries to automatically inject tenant_id filters. In shared-schema mode, uses row-level security (Postgres RLS) or ORM scoping. In separate-schema mode, switches the connection’s search_path. In DB-per-tenant mode, selects the correct connection from a pool registry.

Tenant Configuration Store

Stores per-tenant settings: plan tier, feature flags, rate limits, custom branding, SSO configuration, and data residency requirements. Cached in Redis with tenant_id as the key prefix. Loaded on first request and refreshed periodically.

Resource Quotas & Rate Limiter

Enforces per-tenant limits on API calls, storage, compute, and bandwidth. Prevents noisy neighbor scenarios by throttling tenants that exceed their allocation. Uses token bucket or sliding window algorithms keyed by tenant_id.

Tenant Provisioning Service

Automates new tenant setup: creates database schemas/instances, seeds default data, configures DNS entries, and sets initial quotas. Runs as a background job triggered by signup or plan upgrade.

Tenant Isolation Monitor

Monitors for cross-tenant data access violations, query performance per tenant, and resource consumption anomalies. Alerts on potential noisy neighbor situations and data isolation breaches.

Data Model

Loading diagram...
Multi-Tenant Architecture — Entity relationship diagram

Tenant Identification Strategies

Every request must be mapped to a tenant. Common strategies:

Subdomain-based: acme.yourapp.com → tenant “acme”. Parse the Host header, strip the platform domain, look up the tenant by slug. Simple and user-friendly. Requires wildcard DNS and certificates.

Path-based: yourapp.com/acme/... → tenant “acme”. Works without DNS configuration but pollutes the URL namespace. Less common for customer-facing apps.

Custom domain: app.acme.com → tenant “acme”. Lookup domain in the routing table. Best UX for customers but requires custom domain infrastructure (see Custom Domains guide).

JWT/API key: Extract tenant_id from the authentication token. Works for API-first products. The auth system must embed tenant context in the token at login/key-creation time.

Header-based: X-Tenant-ID header set by an upstream gateway. Used in microservice architectures where a gateway handles tenant resolution and downstream services trust the header.

Row-Level Security with PostgreSQL

PostgreSQL’s Row-Level Security (RLS) provides database-enforced tenant isolation in shared-schema mode.

Setup:

  1. Add tenant_id column to every table
  2. Enable RLS: ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
  3. Create policy: CREATE POLICY tenant_isolation ON orders USING (tenant_id = current_setting('app.tenant_id'));
  4. At request start, set the session variable: SET app.tenant_id = 'tenant_abc';

Benefits: Even if application code forgets to filter by tenant_id, the database enforces it. This is a defense-in-depth strategy — bugs in application code cannot leak data across tenants.

Caveats:

  • RLS adds a small query planning overhead (~1-5%)
  • Superuser roles bypass RLS — never use superuser in the application
  • Must be applied to every table — easy to miss new tables
  • Index on tenant_id is essential for performance
  • Connection poolers (PgBouncer) in transaction mode require SET LOCAL instead of SET

Noisy Neighbor Mitigation

The “noisy neighbor” problem occurs when one tenant’s workload degrades performance for others.

Database layer:

  • Set per-tenant statement timeouts to kill long-running queries
  • Use connection pooling with per-tenant limits (max 10 connections per tenant)
  • Monitor per-tenant query latency and alert on outliers
  • Consider read replicas for heavy-read tenants

Application layer:

  • Per-tenant rate limiting on API endpoints
  • Separate job queues for background tasks (or priority queues with tenant-based priority)
  • Memory/CPU limits per request using timeouts and circuit breakers

Cache layer:

  • Prefix all cache keys with tenant_id to prevent collisions
  • Set per-tenant memory limits or use separate Redis databases
  • Implement cache eviction policies that don’t let one tenant flush others’ cache

Nuclear option: Automatically migrate noisy tenants to dedicated infrastructure when they consistently exceed thresholds. This is the “tiered isolation” approach — start shared, promote to dedicated as needed.

Real-World Examples

Slack

Each workspace is a tenant. Uses shared-schema with workspace_id on every table. Enterprise Grid connects multiple workspaces under one organization with cross-workspace features.

Shopify

Millions of merchant stores on shared infrastructure. Uses a sharded database architecture with pod-based isolation. Large merchants (Shopify Plus) get dedicated resources with higher rate limits.

Salesforce

Pioneered the shared-schema multi-tenant model. All customers share the same database with org_id discrimination. Uses a metadata-driven architecture for per-tenant schema customization.

AWS (Control Plane)

AWS services use a “silo” model for large accounts and “pool” model for smaller ones. Critical control planes run in separate cells to contain blast radius. Each cell serves a subset of tenants.

Architectural Tradeoffs

Shared schema vs database-per-tenant

Pros

  • +Shared: lowest cost, simplest ops, easy cross-tenant features
  • +Per-tenant: strongest isolation, easiest compliance, per-tenant scaling
  • +Shared: migrations are atomic across all tenants

Cons

  • −Shared: data leak risk, noisy neighbor, hard data residency
  • −Per-tenant: high cost, O(N) migrations, complex connection management
  • −Hybrid (tiered): most flexible but most complex to build and operate

Application-level vs database-level isolation (RLS)

Pros

  • +Application-level: flexible, works with any database
  • +Database-level (RLS): defense-in-depth, cannot be bypassed by app bugs
  • +Both together provide the strongest guarantees

Cons

  • −Application-level: single bug can leak data across tenants
  • −Database-level: adds query overhead, complex setup, DB-specific
  • −Both: more development and testing effort

Subdomain vs custom domain tenant routing

Pros

  • +Subdomain: simple DNS, free TLS with wildcard cert
  • +Custom domain: best branding for customers, professional appearance
  • +Both: support both simultaneously for different customer tiers

Cons

  • −Subdomain: less professional, customers want their own domain
  • −Custom domain: complex infrastructure (DNS, TLS, proxy)
  • −Both: more routing logic and edge cases to handle

Learn Multi-Tenant Architecture

Copy a learning context prompt for an AI assistant. It keeps assumptions visible and asks for tradeoffs, cost drivers, failure modes, and what to measure before adding complexity.

Explore More Capabilities