Cache Busting
Technique for forcing browsers and CDNs to fetch a fresh version of a resource by changing its URL. Common methods: appending a version query string (?v=2), using content hashes in filenames (style.a1b2c3.css), or adding build timestamps.
Full Explanation
Cache busting solves a fundamental problem: you told the CDN to cache something for a year, but now you need to update it immediately. Since you can't easily purge every browser cache in the world, you change the URL instead. Different URL = different cache entry = guaranteed fresh fetch.
There are two main approaches. Query string versioning (style.css?v=2) is simple but some CDNs and proxies strip or ignore query strings in cache keys. Filename hashing (style.a1b2c3d4.css) is more reliable because the hash is part of the path, and every CDN respects path changes. Most build tools (Webpack, Vite, esbuild) generate filename hashes automatically.
The best practice is to use long cache TTLs (one year) for hashed assets and short TTLs for the HTML documents that reference them. When you deploy, the HTML points to new hashed filenames, and users automatically get fresh assets. Old versions stay cached until they expire—no purge needed.
Examples
Filename hashing in a build pipeline:
# Webpack output
style.a1b2c3d4.css # hash changes when content changes
app.e5f6g7h8.js
# HTML references the hashed filename
<link rel="stylesheet" href="/static/style.a1b2c3d4.css">
# Cache-Control for hashed assets: cache forever
Cache-Control: public, max-age=31536000, immutable
Nginx config for different cache policies:
# Hashed assets: cache for 1 year
location ~* \.[a-f0-9]{8}\.(css|js|png|woff2)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
# HTML: short cache, always revalidate
location ~* \.html$ {
add_header Cache-Control "public, max-age=60, must-revalidate";
}
Frequently Asked Questions
Technique for forcing browsers and CDNs to fetch a fresh version of a resource by changing its URL. Common methods: appending a version query string (?v=2), using content hashes in filenames (style.a1b2c3.css), or adding build timestamps.
Filename hashing in a build pipeline:
# Webpack output
style.a1b2c3d4.css # hash changes when content changes
app.e5f6g7h8.js
# HTML references the hashed filename
<link rel="stylesheet" href="/static/style.a1b2c3d4.css">
# Cache-Control for hashed assets: cache forever
Cache-Control: public, max-age=31536000, immutable
Nginx config for different cache policies:
# Hashed assets: cache for 1 year
location ~* \.[a-f0-9]{8}\.(css|js|png|woff2)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
# HTML: short cache, always revalidate
location ~* \.html$ {
add_header Cache-Control "public, max-age=60, must-revalidate";
}