Browser Cache
Browser caching is about long-lived caching for static assets (CSS/JS/fonts/images) so repeat visits do not re-download the same files. The main rule: cache assets aggressively, but do not cache personalized HTML in the browser.
Goal: Cache Assets, Not HTML
| Response Type | Typical Header Strategy | Why |
|---|---|---|
| Static assets (versioned) | cache-control: public, max-age=31536000, immutable | Fast repeat views with no revalidation |
| Static assets (not reliably versioned) | shorter TTL + revalidation | Avoid serving broken assets after updates |
| HTML (public pages) | usually short TTL / must-revalidate | HTML freshness is handled by page cache + CDN rules |
| HTML (checkout/account/admin) | no-store | Prevent caching sensitive/personalized content |
Versioning (Cache Busting)
Long cache TTL only works when you have a way to change the URL when the asset changes.
Common strategies:
- Hashed filenames (best):
app.2f3c1d.js - Query string versioning (common in WordPress):
style.css?ver=2.1
If you deploy updates and do not bump versions, visitors can keep old CSS/JS and see broken layouts.
Implementation Examples
Nginx
location ~* \.(css|js|woff2|png|jpg|jpeg|gif|svg|webp|avif|ico)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
}
For checkout/account pages, consider no-store (route examples vary by site):
location ~* ^/(cart|checkout|my-account)/ {
add_header Cache-Control "no-store";
}
LiteSpeed / LSCache
LSCache can set browser cache headers for static assets.
LiteSpeed Cache -> Cache -> Browser
Cloudflare
Cloudflare can influence browser TTL. Prefer setting long TTL for static assets and keep HTML behavior governed by your cache rules/purges.
Verification
Check a static asset:
curl -I https://example.com/wp-content/uploads/hero.webp
You want to see a long max-age (and immutable when appropriate).
Check a sensitive route:
curl -I https://example.com/checkout/
Common Mistakes
| Mistake | What Happens | Fix |
|---|---|---|
| Caching HTML in the browser for dynamic routes | Stale or sensitive content | Use no-store for checkout/account/admin |
| Long TTL without versioning | Broken CSS/JS after deploys | Use hashed filenames or bump ?ver= |
| Multiple layers fight over headers | Confusing behavior | Decide which layer owns headers (origin vs CDN) |