Updated April 2026

Cache Busting Strategies — How to Invalidate Browser and CDN Cache

Quick Answer

The most reliable cache busting strategy is filename hashing — include a content hash in the filename (e.g. app.a3f9d2c.js). The hash changes when content changes, forcing a new cache entry. Query strings (?v=2) work but are less reliable. Cache-Control: no-cache on HTML + immutable on hashed assets is the standard pattern.

Cache busting forces browsers and CDNs to fetch a fresh copy of a resource even when the previous copy hasn't expired. Getting it wrong means users see stale files after a deploy.

Strategy 1 — Filename hashing (recommended)

Include a content hash in the filename. Every build tool supports this.

# Webpack / Vite — output filenames include content hash
output: {
  filename: '[name].[contenthash:8].js',
  chunkFilename: '[name].[contenthash:8].chunk.js',
}

# Result: app.a3f9d2c.js → app.b8d4e1a.js when content changes

With hashed filenames, set max-age=31536000, immutable — the hash is the version. Browsers never need to revalidate.

Cache-Control: public, max-age=31536000, immutable

Strategy 2 — HTML with no-cache

HTML should never be cached immutably. It references your asset filenames. If the HTML is stale, browsers load the old JS/CSS even if the new files are deployed.

Cache-Control: no-cache

# no-cache stores the response but revalidates before serving
# Browser checks: "has the HTML changed?" before using cached version
# If unchanged: serves from cache (304 Not Modified, no data transfer)
# If changed: fetches fresh copy

Strategy 3 — Query string versioning

Less reliable — some CDNs ignore query strings by default. Use only when you can't control filenames.

<script src="/app.js?v=1.2.3"></script>
<link rel="stylesheet" href="/style.css?v=1.2.3">

Strategy 4 — CDN cache purge

# Cloudflare — purge specific URLs
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache"   -H "Authorization: Bearer API_TOKEN"   -H "Content-Type: application/json"   --data '{"files":["https://example.com/app.js"]}'

# Purge everything
--data '{"purge_everything":true}'

# Vercel — automatic on every deployment
# No manual purge needed — new deployment = new CDN cache

Strategy 5 — stale-while-revalidate

Not strictly cache busting, but allows zero-latency deploys. Serve stale content immediately while fetching fresh in background.

Cache-Control: public, max-age=60, stale-while-revalidate=300

# User gets immediate response (stale)
# Background: fresh copy fetched
# Next request: serves the fresh copy

The standard pattern — all together

ResourceCache-ControlWhy
HTMLno-cacheAlways revalidate — references asset filenames
JS/CSS (hashed)public, max-age=31536000, immutableHash = version. Never expires manually.
Images (hashed)public, max-age=31536000, immutableSame as above
Images (unhashed)public, max-age=864001 day — balance freshness vs performance
API (public)public, max-age=60, stale-while-revalidate=300Short cache, background refresh
API (auth)no-storeNever store anywhere