HTTP Caching

[!note] Test note for the books library launch. Covers the stuff I keep looking up.

Why it matters

Every uncached request costs: latency + bandwidth + server load. Caching eliminates repeat work. The browser, CDN, and reverse proxy all participate.

Cache-Control directives

Directive Meaning
max-age=N Resource fresh for N seconds from request time
s-maxage=N Same, but for shared caches (CDNs). Overrides max-age
no-cache Must revalidate before using cached copy (not “don’t cache”)
no-store Never cache at all
immutable Content will never change — skip revalidation forever
private Only browser cache, not CDN
stale-while-revalidate=N Serve stale while fetching fresh in background

[!warning] no-cache does NOT mean “don’t cache”. It means “always revalidate”. Use no-store if you want nothing cached.

Revalidation

When a cached response is stale, the browser revalidates instead of refetching the whole thing:

GET /style.css HTTP/1.1
If-None-Match: "abc123"
If-Modified-Since: Mon, 12 May 2026 10:00:00 GMT

Server responds either:

  • 304 Not Modified (no body, just headers) → browser uses cached copy
  • 200 OK + new body → new content

ETags vs Last-Modified

  • ETag: opaque hash of content. More reliable — works for sub-second changes.
  • Last-Modified: timestamp. Coarser, but simpler to implement server-side.

Prefer ETags when you can.

Heuristic caching

If no Cache-Control header is set, browsers apply heuristic caching:

\[\text{TTL} \approx 0.1 \times (\text{Date} - \text{Last-Modified})\]

Usually caps at 24 hours. Don’t rely on this — always set explicit headers.

Cache busting

For versioned assets (/app.abc123.js), use:

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

The hash in the filename guarantees a new URL on change. The browser never needs to revalidate.

[!tip] immutable tells the browser to not even bother revalidating during the max-age window — no extra network round trip even on hard refresh.


GitHub · RSS