{
    "slug": "api_backwards_compatibility",
    "term": "API Backwards Compatibility",
    "category": "api_design",
    "difficulty": "intermediate",
    "short": "Rules for evolving an API without breaking existing clients — additive changes are safe, removals and renames require versioning, and deprecation needs a documented sunset period.",
    "long": "Safe (backwards-compatible) changes: adding optional fields, adding new endpoints, adding optional query parameters, adding new enum values (with caution — clients must handle unknown values). Breaking changes: removing fields, renaming fields, changing field types, changing response structure, removing endpoints, making optional fields required. Breaking changes require a new API version. Semantic versioning applies: v1 → v2 for breaking changes. Deprecation policy: announce → deprecate (with Deprecation header) → sunset date → remove.",
    "aliases": [
        "API versioning",
        "backwards compatibility",
        "breaking changes",
        "API deprecation"
    ],
    "tags": [
        "api-design",
        "versioning",
        "reliability"
    ],
    "misconception": "Renaming a JSON field is a minor change — renaming breaks every client that reads that field; it is a breaking change requiring a new API version or a transition period with both old and new field names.",
    "why_it_matters": "An API field renamed without versioning silently breaks all clients in production — they receive null where they expected a value with no error, causing subtle bugs that are hard to trace.",
    "common_mistakes": [
        "Removing or renaming fields without a versioning strategy — all existing clients break silently.",
        "Adding required fields to a request body — existing clients don't send the field, their requests fail.",
        "Changing a field from nullable to non-nullable — clients handling null will fail if the type changes.",
        "No deprecation header or sunset date — clients have no warning before a field disappears."
    ],
    "when_to_use": [
        "Public APIs with external consumers who cannot be forced to upgrade on your schedule.",
        "Mobile app APIs where old versions remain in the field for months or years.",
        "Any API covered by an SLA or partner contract that guarantees stability.",
        "After the API has been in production — any change to an existing field is a breaking change."
    ],
    "avoid_when": [
        "Internal APIs consumed only by your own team — strict backwards compatibility slows iteration unnecessarily.",
        "Early-stage APIs still being designed — lock the contract too early and you constrain good design decisions.",
        "Maintaining compatibility for zero consumers — prune unused versions rather than preserving them."
    ],
    "related": [
        "api_versioning",
        "semantic_versioning",
        "rest_constraints",
        "webhook_design"
    ],
    "prerequisites": [
        "api_versioning",
        "semantic_versioning",
        "api_deprecation"
    ],
    "refs": [
        "https://www.mnot.net/blog/2021/10/12/deprecation"
    ],
    "bad_code": "// v1 API response:\n{ \"user_name\": \"alice\", \"user_email\": \"alice@example.com\" }\n\n// 'Refactor' renames fields without versioning:\n{ \"name\": \"alice\", \"email\": \"alice@example.com\" }\n// All clients reading user_name now get undefined/null\n// No errors thrown — silent breakage in production",
    "good_code": "// Additive transition — both names during migration:\n{\n    \"name\": \"alice\",         // New field\n    \"user_name\": \"alice\",    // Kept for backwards compat (deprecated)\n    \"email\": \"alice@example.com\",\n    \"user_email\": \"alice@example.com\" // Kept (deprecated)\n}\n// Deprecation header:\n// Deprecation: Sat, 01 Jan 2027 00:00:00 GMT\n// Link: https://api.example.com/docs/migration; rel=\"deprecation\"\n\n// After sunset: bump to v2 which removes old fields",
    "quick_fix": "Never remove or rename fields in API responses — add new fields instead; deprecate old ones with a Deprecation header and remove only after a migration window",
    "severity": "high",
    "effort": "medium",
    "created": "2026-03-16",
    "updated": "2026-03-25",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/api_backwards_compatibility",
        "html_url": "https://codeclaritylab.com/glossary/api_backwards_compatibility",
        "json_url": "https://codeclaritylab.com/glossary/api_backwards_compatibility.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": "[API Backwards Compatibility](https://codeclaritylab.com/glossary/api_backwards_compatibility) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/api_backwards_compatibility"
            }
        }
    }
}