concept Delivery & performance
HTTP Cache-Control
The HTTP Cache-Control response field describes constraints on storage and reuse of a response.
What it means
Storing an HTTP response is not permission to reuse it indefinitely. A cache must separately decide whether storage is allowed, how freshness is calculated, and whether revalidation is required. max-age=60 supplies a freshness lifetime; s-maxage can override that lifetime for a shared cache. private restricts shared-cache storage, no-cache requires validation before reuse, and no-store forbids storage under the applicable rules. These are not interchangeable. In particular, no-cache does not literally mean “do not store,” and a newly configured no-store value does not erase every old copy already cached elsewhere.
Try it
Simulation — decide store, reuse or validate. Compare private and shared cache with max-age=60, then set age to exactly 60 seconds to see the freshness boundary. Choose max-age=60, s-maxage=300 at age 120: private is stale and shared is fresh. Try no-cache, no-store and private. The result shows storage permission, freshness and next action as separate rows. Reset restores the example.
Cache-Control policy evaluator
Separate permission to store, freshness and need to revalidate in a private or shared cache.
For this fixture, storage eligibility is yes, age 30 s and applicable freshness lifetime 60 s. Fresh means age is strictly less than lifetime. Without a strict revalidation directive, stale reuse still needs an applicable RFC 9111 exception, not automatic permission.
| Observation | Model value |
|---|---|
| Cache | private |
| Directive | max-age=60 |
| Can store? | true |
| Age | 30 s |
| Fresh? | true |
| Next action | Reuse fresh copy |
Local, bounded educational fixture. No DNS, mail, certificate, network, socket or external request is performed.
About this model
Assumes a 200 GET response without Authorization, Vary or heuristic freshness; the example is not a browser cache. For a shared cache, s-maxage overrides max-age and incorporates proxy-revalidate. Changing a new no-store policy does not purge copies already stored elsewhere.
See the article’s protocol sources and model limits. The scene does not alter a real system.
How the mechanism works
Freshness calculation considers the response's apparent age and applicable explicit lifetime, with the simplifying assumptions declared in this exercise. A fresh response may be reused when all other cache-selection rules permit it. no-cache permits storage but requires successful validation before reuse. With no-store, the new response must not be stored under the relevant rule; existing copies elsewhere do not vanish automatically. private blocks storage in shared intermediaries but does not mean the response is encrypted or inaccessible to software running in the user's environment.
A shared cache can use s-maxage, which overrides max-age for its freshness decision. must-revalidate constrains reuse of stale responses after failed validation, not storage of a fresh response. Real caching includes request directives, validators, Vary, Authorization, cache keys, heuristic freshness, stale extensions and other restrictions not implemented in this small model.
Freshness at a shared-cache boundary
Imagine a GET 200 response with Cache-Control: max-age=60, s-maxage=300 and no other restrictions. In a shared cache, s-maxage supplies the 300-second freshness lifetime and includes the effect of proxy-revalidate:
| Current response Age | Shared-cache decision |
|---|---|
| 299 seconds | Fresh under the simplified age rule |
| 300 seconds | Stale: must validate before reuse |
| 301 seconds | Stale: must validate before reuse |
A private cache does not apply s-maxage, so it uses the max-age=60 lifetime for this fixture. Do not misread a cache's stored copy as permission to serve stale personalized data. no-cache is validation-before-reuse, while no-store prohibits newly storing the response and does not magically purge earlier copies.
In practice
When debugging an unexpected stale page, inspect the exact response headers and Age for the specific resource at the browser and any CDN/edge layers. Separate storage from freshness and validation. Confirm any configuration change in a nonproduction environment with explicit request sequences and cache keys. Stop if the route can carry personalized or sensitive content under a shared-cache rule; review the complete application authorization semantics first. Roll back using the previous tested response policy, not an assumption that one directive purges existing content.
Limits and common mistakes
This is a simple 200 GET fixture with no Vary, Authorization or heuristic freshness. Its “fresh” result is conditional on those assumptions and is not a direct probe of a browser or CDN. Cached copies may persist for different durations in other contexts.
Key takeaways
First ask whether a response may be stored; then whether it is still fresh; then whether validation is required for reuse. no-store is not a retroactive purge, while no-cache permits storage but requires validation. Shared caches have different rules for private and s-maxage; s-maxage also includes proxy-revalidate, so a stale shared copy cannot be reused without successful origin validation. At the freshness boundary, equal age is stale.
Frequently asked questions
Editorial questions, answered from the sources listed for this article.
Can no-cache responses be stored?
Yes. no-cache allows storage but requires successful validation before reuse. no-store is the distinct storage prohibition.
Does s-maxage override max-age in my browser cache?
No. In this example s-maxage applies to a shared cache; a private cache uses its applicable freshness directives. A shared cache using s-maxage also has a strict revalidation constraint when stale.
Sources & model boundaries
Primary references used for this explanation. The interactive example is an educational model, not a live check.
- HTTP Caching
Storage, cache freshness and revalidation (§§3–5). Cache directives, freshness, validation and shared/private restrictions.
Checked .
- MDN — Cache-Control header
Cache-Control directives with private/shared cache examples. Practical semantics; no-cache versus no-store and shared overrides.
Checked .