Asset Versioning & Browser Cache Strategy
Also Known As
browser caching
static asset cache
cache busting
TL;DR
Serving static assets with immutable long-lived cache headers plus content-hash filenames — maximising cache hits while guaranteeing instant cache-busting on change.
Explanation
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.
Diagram
flowchart LR
subgraph No Content Hash
BROWSER[Browser] -->|GET app.css| SERVER[Server]
SERVER -->|200 app.css v1| BROWSER
DEPLOY[New deploy v2] --> SERVER
BROWSER -->|cached - serves v1!| OLD[Stale CSS]
end
subgraph Content Hash in Filename
B2[Browser] -->|GET app.a3f2c.css| S2[Server]
S2 -->|200 Cache-Control: max-age=31536000| B2
DEPLOY2[New deploy] --> NEW[app.b7d9e.css - new hash]
B2 -->|new filename - fetches fresh| FRESH[Always fresh]
end
style OLD fill:#f85149,color:#fff
style FRESH fill:#238636,color:#fff
Common 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.
Code Examples
✗ Vulnerable
// Version query string — proxy-unfriendly cache busting:
<script src="/app.js?v=1.2"></script>
// Content-hash filename — correct approach:
<script src="/app.abc123f.js"></script>
<!-- Server: Cache-Control: public, max-age=31536000, immutable -->
✓ Fixed
// Content-hash filenames + immutable cache headers
// Build tool (Vite) output: app.a3f8d2b1.js
// PHP: read Vite manifest to resolve hashed filenames
$manifest = json_decode(file_get_contents(public_path('build/manifest.json')), true);
$assetUrl = '/build/' . $manifest['resources/js/app.js']['file'];
// → /build/assets/app-a3f8d2b1.js
// Serve with immutable header (nginx)
location ~* \.(js|css|woff2|png|webp)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Vary Accept-Encoding;
}
// HTML document: no-cache so browsers always check for new asset filenames
add_header Cache-Control "no-cache, must-revalidate";
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
33
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Perplexity 7
Amazonbot 6
Google 4
SEMrush 3
Unknown AI 2
Ahrefs 2
Also referenced
How they use it
crawler 21
crawler_json 3
Related categories
⚡
DEV INTEL
Tools & Severity
🟠 High
⚙ Fix effort: Low
⚡ 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
📦 Applies To
any
web
🔗 Prerequisites
🔍 Detection Hints
Static assets without content hash in filename; Cache-Control missing on CSS/JS; assets with very short max-age requiring frequent revalidation
Auto-detectable:
✓ Yes
lighthouse
curl
webpack
vite
⚠ Related Problems
🤖 AI Agent
Confidence: Medium
False Positives: Low
✓ Auto-fixable
Fix: Low
Context: File