Crux Read real Cache-Control headers and a CDN response, predict how browser and CDN behave, and pick the correct directive for the scenario.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 14 min
Cache bugs are read off the wire — in the response headers and the CDN’s cache-status line. Read each header set, predict what every tier in the chain does with it, then pick the fix a senior engineer would ship.
Goal
Practise the loop you run in every caching incident: read the directives, reason about browser vs shared-cache behaviour separately, and choose the directive that matches the data’s sharing and freshness needs.
Snippet 1 — the “secure” endpoint
GET /api/account/balance HTTP/1.1200 OKCache-Control: no-cacheContent-Type: application/json
Quiz
Completed
This per-user balance endpoint ships no-cache and no ETag. What is the real behaviour, and what should it ship instead?
Heads-up no-cache permits storage and only forces revalidation; it never prevents storage. Per-user financial data needs no-store, which forbids storage everywhere.
Heads-up An ETag fixes revalidation efficiency but the response is still stored — in the browser and bfcache. The data must not be stored at all, so no-store is required regardless of the ETag.
Heads-up s-maxage=0 still permits storage and only forces shared-cache revalidation; it also says nothing about the browser. The correct exclusion for per-user data is private, no-store.
This header is on the site's index.html, served through a CDN. What goes wrong, and what is the correct header for HTML that references content-hashed assets?
Heads-up A CDN purge cannot reach a browser holding the HTML for a year; that client keeps the stale document. HTML must be revalidated by the browser, so it should not carry a year-long max-age.
Heads-up Browsers honor max-age for HTML just like any resource; max-age=31536000 makes the browser hold it a year too. There is no automatic HTML revalidation when max-age is large.
Heads-up immutable makes it worse — it tells the browser to never revalidate even on reload, freezing the stale HTML harder. The rule is to hash assets, never the HTML.
A search-results page that is cheap to revalidate and not sensitive uses Response A; a password-reset page uses Response B. Is each choice right?
Heads-up no-cache on the reset page permits storage and only requires revalidation — the sensitive page would still be stored and in bfcache. no-store is required for the reset page; A's revalidation is exactly right for cheap, non-sensitive search results.
Heads-up no-cache means revalidate before reuse, not never reuse. A 304 lets the cache serve the stored body for free, so a stable result is reused efficiently — that is the point of pairing no-cache with an ETag.
Heads-up no-store on the search page throws away all caching for non-sensitive content that revalidates cheaply, hurting performance for no security gain. Match the directive to the data: no-store only where storage itself is the risk.
Snippet 4 — the CDN response line
200 OKCache-Control: max-age=60, s-maxage=300, stale-while-revalidate=3600Age: 420CF-Cache-Status: HIT
Quiz
Completed
The CDN returns this for a JSON API. Age=420 exceeds s-maxage=300, yet it is a HIT. Is this correct, and what is the client getting?
Heads-up stale-while-revalidate explicitly authorizes serving stale within its window and counting it as a HIT while a background revalidate runs. That is the feature, not a bug.
Heads-up max-age=60 is the browser's freshness; the CDN copy is governed by s-maxage. Whether the browser revalidates depends on what the CDN returns now, but the CDN HIT here is valid under stale-while-revalidate.
Heads-up HIT means served from cache, not that it is fresh. Under stale-while-revalidate a stale copy is served as a HIT; freshness is determined by Age vs s-maxage, which here says stale-but-serveable.
Recap
Every caching bug is read from headers. no-cache without an ETag on per-user data is a stored, inefficiently-revalidated leak — ship private, no-store instead. A year-long max-age on HTML freezes deploys, because the rule is to hash assets and keep HTML revalidating. no-cache plus an ETag is the right choice for cheap, non-sensitive content that reuses via 304; no-store is for data that must never be stored at all. And a CDN HIT with Age past s-maxage is correct under stale-while-revalidate — stale-but-instant by design, with a background refresh. Read the directives per tier, match them to the data’s sharing and sensitivity, then verify on the wire.