{
    "slug": "asset_caching",
    "term": "Asset Versioning & Browser Cache Strategy",
    "category": "performance",
    "difficulty": "beginner",
    "short": "Serving static assets with immutable long-lived cache headers plus content-hash filenames — maximising cache hits while guaranteeing instant cache-busting on change.",
    "long": "The optimal static asset strategy: append a content hash to filenames (app.a3f8d2.js) and serve with Cache-Control: public, max-age=31536000, immutable. Browsers cache indefinitely; on next deploy the hash changes so the new filename is fetched fresh — no stale asset problem. The HTML document itself gets Cache-Control: no-cache, must-revalidate so it always reflects the latest asset filenames. Build tools (Vite, Webpack, Laravel Mix) handle hash generation and manifest files that PHP uses to resolve hashed filenames. For PHP-served dynamic content: use ETag or Last-Modified headers and respond with 304 Not Modified to save bandwidth. Avoid query-string versioning (?v=123) — some CDNs and proxies strip or ignore query strings when caching.",
    "aliases": [
        "browser caching",
        "static asset cache",
        "cache busting"
    ],
    "tags": [
        "performance",
        "http",
        "frontend",
        "caching"
    ],
    "misconception": "Setting a long Cache-Control max-age means users always get stale assets after a deployment. Cache busting via content-hashed filenames (app.a1b2c3.js) lets you set immutable long-lived cache headers while guaranteeing users receive updated files immediately after deployment.",
    "why_it_matters": "Long cache lifetimes for static assets eliminate repeated downloads — cache-busting via content hashes ensures users get updated files immediately without waiting for cache expiry.",
    "common_mistakes": [
        "Using a query string for cache-busting (?v=2) — some proxies ignore query strings and serve stale content.",
        "Short Cache-Control max-age on static assets — defeats the performance benefit.",
        "Not using immutable directive for fingerprinted assets — browsers may still revalidate without it.",
        "Cache-Control: no-cache on static assets in production — every request hits the server."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "http_caching",
        "php_output_compression",
        "cdn",
        "error_budget"
    ],
    "prerequisites": [
        "http_caching",
        "js_bundling_concepts",
        "nginx_php_fpm_config"
    ],
    "refs": [
        "https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching"
    ],
    "bad_code": "// Version query string — proxy-unfriendly cache busting:\n<script src=\"/app.js?v=1.2\"></script>\n\n// Content-hash filename — correct approach:\n<script src=\"/app.abc123f.js\"></script>\n<!-- Server: Cache-Control: public, max-age=31536000, immutable -->",
    "good_code": "// Content-hash filenames + immutable cache headers\n// Build tool (Vite) output: app.a3f8d2b1.js\n\n// PHP: read Vite manifest to resolve hashed filenames\n$manifest = json_decode(file_get_contents(public_path('build/manifest.json')), true);\n$assetUrl = '/build/' . $manifest['resources/js/app.js']['file'];\n// → /build/assets/app-a3f8d2b1.js\n\n// Serve with immutable header (nginx)\nlocation ~* \\.(js|css|woff2|png|webp)$ {\n    add_header Cache-Control \"public, max-age=31536000, immutable\";\n    add_header Vary Accept-Encoding;\n}\n\n// HTML document: no-cache so browsers always check for new asset filenames\nadd_header Cache-Control \"no-cache, must-revalidate\";",
    "quick_fix": "Serve hashed filenames (app.abc123.js) with Cache-Control: immutable, max-age=31536000 — the hash changes when content changes, so the cache is always correct",
    "severity": "high",
    "effort": "low",
    "created": "2026-03-15",
    "updated": "2026-03-22",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/asset_caching",
        "html_url": "https://codeclaritylab.com/glossary/asset_caching",
        "json_url": "https://codeclaritylab.com/glossary/asset_caching.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": "[Asset Versioning & Browser Cache Strategy](https://codeclaritylab.com/glossary/asset_caching) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/asset_caching"
            }
        }
    }
}