{
    "slug": "cloud_multi_tenancy",
    "term": "Cloud Multi-Tenancy",
    "category": "cloud",
    "difficulty": "intermediate",
    "short": "Serving multiple customers (tenants) from shared infrastructure while keeping their data and behaviour isolated.",
    "long": "Multi-tenancy is an architecture where a single deployment of an application serves many customers, called tenants. Instead of spinning up one full stack per customer, tenants share compute, networking, and often the same database - while the application enforces strict isolation so no tenant can see or affect another's data. This is the dominant SaaS model because it amortises infrastructure cost and operational effort across the whole customer base.\n\nIsolation can sit at several layers. Database-level options range from a shared database with a tenant_id column on every row (cheapest, hardest to isolate), to a schema per tenant, to a full database per tenant (strongest isolation, highest overhead). Application-level isolation requires that every query is scoped by tenant, usually by injecting a tenant context early in the request lifecycle (from subdomain, header, or JWT claim) and threading it through repositories and caches.\n\nThe central risk is cross-tenant data leakage: a missing WHERE tenant_id = ? clause, a cache key that omits the tenant, or a background job that runs without tenant scope can expose one customer's data to another. These bugs are catastrophic for trust and often violate contractual and regulatory boundaries. Robust designs make tenant scoping the default rather than something each query opts into - global query scopes, row-level security in PostgreSQL, or a connection-per-tenant strategy that physically separates data.\n\nNoisy-neighbour effects are the other recurring problem: one heavy tenant consuming shared CPU, connections, or rate limits degrades everyone. Mitigations include per-tenant quotas, connection pool partitioning, and tiering large tenants onto dedicated infrastructure. Choosing a tenancy model is a trade-off between cost efficiency, isolation strength, and per-tenant customisation, and it is expensive to change later, so decide deliberately up front.",
    "aliases": [
        "multitenancy",
        "saas tenancy",
        "tenant isolation"
    ],
    "tags": [
        "cloud",
        "saas",
        "tenant-isolation",
        "architecture",
        "data-isolation"
    ],
    "misconception": "Multi-tenancy just means giving each customer a subdomain. In reality it means every layer - queries, caches, jobs, and rate limits - must be scoped by tenant, or data from one customer leaks into another.",
    "why_it_matters": "A single un-scoped query in a multi-tenant app can expose one customer's data to another, breaching contracts and regulations; the tenancy model also dictates cost and the blast radius of every change.",
    "common_mistakes": [
        "Forgetting the tenant_id filter on a query, exposing another tenant's rows.",
        "Cache keys that omit the tenant, so one customer sees another's cached data.",
        "Background jobs and migrations that run without tenant context.",
        "No per-tenant quotas, letting one heavy tenant degrade everyone (noisy neighbour).",
        "Picking a shared-database model for customers with strict isolation or compliance needs."
    ],
    "when_to_use": [
        "Building SaaS that must serve many customers cost-effectively from one codebase.",
        "Tenants share the same feature set with data isolation as the main requirement.",
        "You can enforce tenant context centrally via middleware, global scopes, or row-level security."
    ],
    "avoid_when": [
        "A single customer needs full physical isolation for compliance - a dedicated single-tenant deployment is simpler and safer.",
        "Heavy per-tenant customisation of schema or behaviour would require constant branching of shared code.",
        "The team cannot guarantee tenant scoping is enforced by default across queries, caches, and jobs."
    ],
    "related": [
        "cloud_databases",
        "cloud_security_shared_model",
        "cloud_native_patterns",
        "authorization"
    ],
    "prerequisites": [
        "cloud_databases",
        "authorization",
        "cloud_computing_models"
    ],
    "refs": [
        "https://docs.aws.amazon.com/wellarchitected/latest/saas-lens/saas-lens.html",
        "https://www.postgresql.org/docs/current/ddl-rowsecurity.html",
        "https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/overview"
    ],
    "bad_code": "<?php\n// Tenant filter is opt-in - easy to forget, leaks across tenants\nclass InvoiceRepository\n{\n    public function __construct(private PDO $db) {}\n\n    public function find(int $id): ?array\n    {\n        // No tenant scoping at all - any tenant can read any invoice\n        $stmt = $this->db->prepare('SELECT * FROM invoices WHERE id = ?');\n        $stmt->execute([$id]);\n        return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;\n    }\n}",
    "good_code": "<?php\n// Tenant context resolved once, enforced on every query\nfinal class TenantContext\n{\n    public function __construct(public readonly int $tenantId) {}\n}\n\nclass InvoiceRepository\n{\n    public function __construct(\n        private PDO $db,\n        private TenantContext $tenant,\n    ) {}\n\n    public function find(int $id): ?array\n    {\n        $stmt = $this->db->prepare(\n            'SELECT * FROM invoices WHERE id = ? AND tenant_id = ?'\n        );\n        $stmt->execute([$id, $this->tenant->tenantId]);\n        return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;\n    }\n}\n// Even stronger: PostgreSQL RLS so the database rejects un-scoped reads.",
    "quick_fix": "Inject tenant context at the request boundary and enforce it with a global query scope or PostgreSQL row-level security so tenant filtering is the default, not opt-in.",
    "severity": "high",
    "effort": "high",
    "created": "2026-06-09",
    "updated": "2026-06-09",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/cloud_multi_tenancy",
        "html_url": "https://codeclaritylab.com/glossary/cloud_multi_tenancy",
        "json_url": "https://codeclaritylab.com/glossary/cloud_multi_tenancy.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Cloud Multi-Tenancy](https://codeclaritylab.com/glossary/cloud_multi_tenancy) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/cloud_multi_tenancy"
            }
        }
    }
}