Contents

Web & Networking › HTTP · also in Caching

HTTP Caching

Cache-Control, ETag and Last-Modified for reusing responses.

Also known as: browser caching, Cache-Control header, ETag, Last-Modified, HTTP cache, cache headers

HTTP lets responses be stored and reused, by the browser or by shared caches such as CDNs, so repeat requests are fast or never reach your server. You control it with response headers.

Two questions the cache answers

1. Is my stored copy still fresh? (Cache-Control, a lifetime)

Cache-Control: max-age=31536000, immutable

For the next year, reuse the copy without asking the server at all.

2. If it’s stale, has it actually changed? (validators: ETag or Last-Modified)

# First response
ETag: "v42-9f3a"

# Later request (the browser asks "do you still have this version?")
If-None-Match: "v42-9f3a"

# Server: nothing changed, so use your copy
HTTP/1.1 304 Not Modified

A 304 has no body, so it saves bandwidth, though it still costs a round trip (conditional requests, ETag).

The Cache-Control directives to know

DirectiveMeaning
max-age=NFresh for N seconds
no-cacheCan be stored, but must be revalidated with the server before each use (the name misleads!)
no-storeDon’t store it at all: for sensitive data
privateOnly the user’s browser may cache it, not shared caches like CDNs
publicShared caches may store it
immutableNever changes, so don’t revalidate
stale-while-revalidate=NServe a stale copy while refreshing in the background

A practical strategy

  • Static assets with hashed filenames (app.8f3a2c.js): cache for a year with immutable. A new build gets a new filename, so there’s nothing to invalidate (asset hashing).
  • HTML pages: no-cache (always revalidate) or a short max-age, so users pick up new deploys.
  • API responses: decide per endpoint. User-specific data is private (or no-store). Public data can use a short max-age.
  • Sensitive data (account pages, tokens): no-store.

Gotchas

  • Caching problems are “invisible bugs”: a user sees an old version, and you can’t reproduce it. Check the network tab for “(disk cache)” and the headers.
  • Without any headers, browsers may apply heuristic caching, so set them explicitly.
  • Vary tells caches which request headers change the response (Vary: Accept-Encoding, Accept-Language). Missing it can serve the wrong variant.
  • Don’t cache personalized responses in a shared cache. Use private.
  • You can’t recall a copy that’s sitting in a browser with a long max-age. That’s why URLs, not headers, are the way to bust caches.

See Cache-Control and CDN caching.