Part III β The Speed Β· Lesson 6.7
HTTP Caching
In one lineTwo headers decide whether a request happens at all, and whether it costs a full download.
Where you've seen itA repeat visit where the JavaScript loads in 2ms from disk, and DevTools shows no network request whatsoever.
Diagram
THE DECISION FLOW β the browser runs this for every request
need a resource
β
βΌ
in cache? ββ no βββββββββββββββββββββββββββΊ fetch from network
β yes
βΌ
still fresh? (age < max-age)
β
ββββββ΄ββββββ
yes no
β β
βΌ βΌ
use it revalidate: send If-None-Match: "<etag>"
0ms, β
no request βββββββ΄βββββββ
βΌ βΌ
304 Not Modified 200 + new body
(headers only, (full download)
~200 bytes)THE TWO STRATEGIES β and when each is correct
IMMUTABLE ASSETS (hashed filenames)
Cache-Control: public, max-age=31536000, immutable
app.7b2e04.js βββΊ never revalidated for a year
new deploy βββΊ app.9d1f77.js βββΊ different URL, fresh fetch
β zero requests, zero staleness. Requires content hashing.
MUTABLE DOCUMENTS (HTML, API responses)
Cache-Control: no-cache
β misleading name: "cache it, but ALWAYS revalidate first"
βββΊ 304 in ~1 RTT if unchanged, cheap and always correct
NEVER STORE (personal data on shared machines)
Cache-Control: no-store, privateSTALE-WHILE-REVALIDATE β instant AND eventually fresh
Cache-Control: max-age=60, stale-while-revalidate=3600
t=0 fetch, cache
t=30s β fresh β serve from cache
t=300s stale but within β serve STALE instantly (0ms)
the SWR window + refresh in background
t=2h beyond window β blocking fetchHow it works
Cache-Controlsets freshness. While fresh, the browser doesn't ask the network at all β the fastest possible request is the one not made.ETag/Last-Modifiedenable revalidation. Once stale, the browser asks "has it changed?"; a304costs headers only.immutable+ content-hashed filenames is the whole game for static assets: cache for a year and change the URL on deploy.Varymatters.Vary: Accept-Encodingis normal;Vary: Cookieeffectively disables shared caching.- Private vs shared:
privatemeans browser-only,publicallows CDNs and proxies. Get this wrong on a personalised page and users see each other's data.
Trade-offs
| Header combo | Result |
|---|---|
max-age=31536000, immutable | Perfect for hashed assets |
no-cache | Always revalidate; cheap and safe for HTML |
no-store | Never cached β auth pages, personal data |
max-age=3600 on HTML | Users stuck on an old app for an hour |
s-maxage | Different TTL for CDN vs browser |
Interview angle
"You deployed but users still see the old version. Why?"
- The HTML was cached with a
max-age, so browsers never asked for the new one and kept referencing old asset URLs. - Correct split:
no-cacheon the HTML document,immutable+ longmax-ageon hashed assets. - Purge the CDN for the document too β the edge can hold a stale copy even after the origin updates.
Recap
- Fresh = no request at all; stale = a cheap
304revalidation. - Hash your filenames and cache them for a year; never cache the HTML that points at them.
stale-while-revalidatebuys instant responses without long-term staleness.