HTTP Caching Without Guesswork: Cache-Control, ETag, Vary and Versioned Assets

Choose policy by response type and verify it with requests, not browser folklore

HTTP Caching Without Guesswork: Cache-Control, ETag, Vary and Versioned Assets

A standards-based cache policy matrix for HTML, hashed assets, public API data and authenticated responses.

Reliable HTTP caching starts by deciding who may reuse a response, for how long and how freshness will be validated; it does not start with a copied kitchen-sink header.

RFC 9111 defines caching behavior, while browsers and managed caches add operational controls. A response can be stored yet require validation, remain fresh for a period, or be excluded from storage. The correct policy depends on whether the URL is versioned, the body is personalised and the origin can produce validators.

Freshness and validation solve different problems

A fresh response can be reused without contacting the origin. A stale response may be validated with ETag/If-None-Match or Last-Modified/If-Modified-Since, allowing a 304 response when unchanged. Cache-Control: no-cache permits storage but requires validation before reuse in the relevant context; no-store instructs caches not to store the response. Their names are easy to misread.

Version static assets instead of purging by hope

When a file URL changes with its content, such as app.4f3a.js, the response can use a long freshness lifetime and immutable. A deployment references the new URL; old documents can still load the old asset. Do not apply that policy to stable HTML URLs whose content changes without a new URL, because clients would keep stale pages until freshness expires.

Protect personalised responses

Private marks a response for a private cache rather than shared intermediaries; it does not mean encrypted or secret. Authenticated HTML and API responses need explicit analysis of cookies, authorisation and cache keys. Vary tells caches which request headers select a representation, but varying on high-cardinality or uncontrolled headers can fragment the cache and still miss application-level identity.

Verify the entire request sequence

Inspect the first response, then repeat while fresh and after forced or natural revalidation. Record Age, Cache-Control, ETag, Last-Modified, Vary and status. Test anonymous and authenticated cases separately. A CDN purge is a product operation, not a general deletion mechanism defined by HTTP; design URLs and lifetimes so correctness does not depend on emergency purges.

Starting cache-policy matrix

ResponseTypical starting pointVerify
Hashed JS/CSS/imagepublic, long max-age, immutableURL changes when bytes change
Public HTMLno-cache plus validators304 occurs when representation is unchanged
Short-lived public APIexplicit short freshness and validatorShared cache key includes real variants
Personalised responseprivate/no-cache or no-store after analysisNo cross-user shared-cache reuse

Implementation review

  1. Classify each response by audience and mutability.
  2. Give every response an explicit policy.
  3. Use validators where revalidation is useful.
  4. Limit Vary to real representation dimensions.
  5. Test sequences at browser, CDN and origin boundaries.

Examples were reviewed against RFC 9111 and MDN on 4 September 2026. Treat them as policy patterns, then confirm the behavior of the browser, framework and managed cache actually deployed.

Sources

Related