HTTP Caching Headers
Cache-Control, ETag, Last-Modified, Vary, and immutable fingerprinting patterns for static vs HTML.
- browser
- http-cache
- cache-control
- etag
- performance
The fastest request is one the browser never sends. HTTP caching is controlled primarily by response headers. Frontend builds (content hashes) and CDN config make or break production performance and “users stuck on old JS” incidents.
Docs: MDN HTTP caching, web.dev HTTP cache, RFC 9111.
Cache-Control essentials
Cache-Control: max-age=31536000, immutable
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: private, max-age=0, must-revalidate
| Directive | Meaning |
|---|---|
max-age=N |
Fresh for N seconds from response |
immutable |
Won’t revalidate on reload while fresh (great for hashed assets) |
no-cache |
Store but revalidate before use |
no-store |
Don’t store (sensitive) |
private |
Browser OK; shared CDN should not store |
public |
Shared caches may store |
stale-while-revalidate |
Serve stale while revalidating (where supported) |
Fingerprinted static assets (best pattern)
Build emits /app.9f3c2a.js. Deploy headers:
Cache-Control: public, max-age=31536000, immutable
HTML references the new hash on release → clients fetch new file; old hash can stay cached forever. See Caching static assets.
HTML / app shell
Usually short freshness or revalidate so deploys propagate:
Cache-Control: no-cache
ETag: "abc123"
no-cache still allows storing; browser checks with conditional requests.
Validators: ETag and Last-Modified
ETag: "v3-deadbeef"
Last-Modified: Tue, 04 Aug 2026 12:00:00 GMT
Browser revalidates:
If-None-Match: "v3-deadbeef"
Server: 304 Not Modified without a body when unchanged — saves download, still costs a round trip.
Vary
Vary: Accept-Encoding
Vary: Origin
Caches must key on listed request headers. Wrong Vary causes cache poisoning or cache misses. CORS responses that differ by Origin should Vary: Origin.
Heuristic caching
Without explicit headers, some caches guess from Last-Modified. Don’t rely on heuristics for SPAs — set explicit Cache-Control.
Service workers vs HTTP cache
SW caches API is separate. A fetch may hit HTTP cache underneath depending on request mode and SW strategy. Debug with Network panel “size” column (disk/memory cache vs SW).
Common incidents
- HTML cached forever → users stuck on old entry that points at deleted hashed files.
- JS without hash + long max-age → same stuck state.
no-storeon everything → slow, expensive, no offline.- CDN ignores
privatemisconfig → shared user data (security bug).
Interview out-loud
“Hashed static assets get long max-age and immutable. HTML revalidates with no-cache or short max-age plus ETag. Vary must match response variance. Caching bugs are usually HTML cached too long or assets without fingerprints cached too long.”
Deploy smoke tests
After each release: open Network, verify HTML is revalidated or short-cached, and /assets/*hash* returns immutable long cache. Hit an old hashed URL intentionally — 404 is better than wrong content. For CDNs with layered caches, purge HTML on release; don’t rely on multi-hour HTML TTLs for apps that ship multiple times a day.
Related
- Caching static assets fingerprinting
- Browser DevTools Network panel
- Service workers overview
- Compression gzip Brotli
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
Related guides
- BFCache Back Forward CacheHow the back/forward cache freezes pages for instant history nav, what blocks it, and how to restore state safely.
- Browser DevTools Network PanelRead waterfalls, timing phases, headers, throttling, and initiator chains in the Network panel like a production debugger.
- Browser DevTools Performance PanelRecord main-thread timelines: long tasks, style/layout/paint, frames, and how to turn flame charts into INP fixes.
- Browser Networking 101DNS, TCP/TLS, HTTP/1.1 vs H2/H3, connection reuse, and what frontend code can actually influence.
- Compositor LayersWhen browsers promote layers, why transform/opacity animate cheaply, and layer explosion costs.