Explain the difference between the HTTP response headers `Cache-Control: no-cache`, `Cache-Control: no-store` and `Cache-Control: must-revalidate`, and give a case where each is the right choice.
answer
- store vs reuse: two different steps
- no-store = never write it down
- no-cache = stored, but ask first (304 is cheap)
- must-revalidate only bites after expiry → 504 not stale
- Pragma: no-cache is a deprecated HTTP/1.0 relic
basics
~20 sno-store means never write this to any cache. no-cache means you may store it but must check with the origin before every reuse. must-revalidate means you may serve it freely while fresh, but once it expires you must revalidate rather than serve it stale. Use no-store for secrets, no-cache for always-current data, must-revalidate when stale answers are unacceptable.
solid answer
~60 sThey sit at three different points of the lifecycle. - **`no-store`** — do not write the response (or request) to any storage, shared or private. This is the privacy directive: bank statements, password-reset pages, anything you do not want on disk or in a proxy. - **`no-cache`** — storing is fine, *reuse* is not, until the cache revalidates with the origin. A 304 makes reuse legal and cheap. Use it for content that must always be current but rarely changes, such as an HTML shell you want re-checked on every navigation — it saves bandwidth without risking staleness. - **`must-revalidate`** — only bites once the response is already stale. It forbids the cache from serving a stale copy when the origin is unreachable; the cache must return an error, typically 504, instead. Use it where a wrong answer is worse than no answer, such as an account balance. The classic mistake is reading `no-cache` as "do not cache". It means "do not reuse without asking". `no-store` is the one that means do not cache.
code
http · 11 linesHTTP/1.1 200 OK
Cache-Control: no-store
Content-Type: text/html
HTTP/1.1 200 OK
Cache-Control: no-cache
ETag: "a1b2c3"
HTTP/1.1 200 OK
Cache-Control: max-age=600, must-revalidate
ETag: "d4e5f6"go deeper
Nail the one-liners: no-store = never save it, no-cache = save it but ask before reusing, must-revalidate = no stale after expiry.
Explain the store-versus-reuse split and note that no-cache still saves bandwidth via 304 responses.
Discuss the failure modes — sensitive data left stored under no-cache, the 504 behaviour of must-revalidate during an origin outage, and the latency cost of no-cache on assets.
Frame it as a policy decision per response class and set defaults at the edge so individual services cannot accidentally leak or over-revalidate.
## A cache does two separable things An HTTP cache **stores** a response and later **reuses** it. Almost all confusion around these directives comes from collapsing those two steps. `no-store` targets storing; `no-cache` targets reusing; `must-revalidate` targets reusing *after expiry*. ## no-store `Cache-Control: no-store` instructs every cache — the browser's disk cache, a corporate proxy, a CDN, an intermediate reverse proxy — not to write any part of the request or response to persistent or non-volatile storage. It is the strongest directive and the only one that is really about confidentiality. Send it on responses whose contents must not survive the transaction: financial detail pages, password reset flows, one-time codes, anything with a session-bound secret in the body. Two caveats. First, `no-store` is not a security control on its own — it is a request to well-behaved caches, and it does nothing about screenshots, swap files or logs. Second, it does not imply `private`, and pairing `no-store` with the belief that the data is now protected end to end is a common over-read; TLS and authorization do the actual protecting. ## no-cache `Cache-Control: no-cache` permits storage but requires **successful revalidation with the origin server before any reuse**. The stored copy is not wasted: on the next request the cache issues a conditional request, and if the origin answers `304 Not Modified` the cache serves its copy without re-downloading the body. So `no-cache` costs you a round trip but saves the payload — which is exactly what you want for a resource that must never be stale but usually has not changed, such as the HTML document that references fingerprinted assets. RFC 9111 also allows the qualified form `no-cache="Set-Cookie"`, meaning shared caches must strip the named fields before reusing the stored response rather than revalidate the whole thing. Support is thin and it applies only to shared caches. ## must-revalidate `Cache-Control: must-revalidate` does nothing while a response is fresh — that is the point people miss. `max-age=600, must-revalidate` serves from cache for ten minutes with no origin contact at all. Its effect starts at expiry: normally a cache is *allowed* to serve a stale response in some circumstances (notably when the origin is unreachable), and `must-revalidate` removes that permission. If revalidation cannot be completed, the cache must generate an error — `504 Gateway Timeout` — rather than hand back stale content. `proxy-revalidate` is the same rule restricted to shared caches, leaving private browser caches free to serve stale. ## Putting them together - `no-store` — sensitive, must not persist anywhere. - `no-cache` — must be current on every use; revalidation keeps it cheap. - `max-age=N, must-revalidate` — cheap for N seconds, then strictly correct or an error. - `max-age=N` alone — cheap for N seconds, then revalidate, with the cache permitted to fall back to stale if the origin is down. The combination `no-cache, no-store, must-revalidate` appears in countless codebases as a cargo-cult "do not cache" string. It is not wrong, merely redundant: `no-store` already forbids storage, so the other two have nothing to act on. `Pragma: no-cache` is often bolted on too; it is an HTTP/1.0 request-header artefact, ignored as a response header by modern caches, and RFC 9111 deprecates it. ## Where a wrong choice hurts Marking an API response `no-cache` when you meant `no-store` leaves sensitive JSON sitting in a shared proxy's storage — legal to store, merely revalidated before reuse. Marking a static asset `no-cache` when you meant a long `max-age` costs a conditional request on every page load, which on a high-latency mobile connection is far more expensive than the bytes you saved. And relying on `must-revalidate` to keep content current while it is still fresh does nothing at all — you need a shorter `max-age`.
- Does `no-cache` prevent the response from being written to disk?No. It explicitly permits storage and only forbids reuse without revalidating against the origin first. A shared proxy or browser cache may keep the bytes on disk indefinitely under `no-cache`. If the concern is the data existing at rest, `no-store` is the directive you need.
- If a response is `max-age=600, must-revalidate` and the origin is unreachable at second 700, what does the cache do?It must not serve the stale copy. `must-revalidate` removes the cache's normal permission to serve stale content when it cannot reach the origin, so it generates an error response, conventionally 504 Gateway Timeout. Without `must-revalidate`, the cache would be allowed to serve the stale copy instead.
- Is `Cache-Control: no-cache, no-store, must-revalidate` wrong?Not wrong, just redundant. `no-store` already forbids storing the response, so there is nothing left for `no-cache` or `must-revalidate` to govern. The string persists as a copy-paste defensive incantation aimed at very old caches; on modern caches `no-store` alone is sufficient.
saying these in an interview costs you the question
- Reading `no-cache` as "do not cache" — it means "do not reuse without revalidating"
- Believing `must-revalidate` forces a check on every request while the response is still fresh
- Using `no-cache` for sensitive data that must not be written to disk
- Adding `Pragma: no-cache` as a response header and expecting modern caches to honour it
- Assuming `no-store` gives any confidentiality guarantee beyond a request to cooperating caches