Cache-Control Directives Reference
Cache-Control defines how browsers and shared caches may store, validate, and reuse a response. Set policy by content type and URL lifecycle rather than applying one long lifetime to the whole site.
Core response directives
| Directive | Practical meaning |
|---|---|
| no-store | Do not store the response in caches. |
| no-cache | Storage is allowed, but validation is required before reuse. |
| max-age=N | The response is fresh for N seconds after generation. |
| s-maxage=N | Overrides freshness for shared caches such as CDNs. |
| private | Do not store in shared caches; a private browser cache may store it. |
| public | Explicitly permits shared-cache storage when other rules allow it. |
| must-revalidate | Once stale, the response must be validated before reuse. |
| immutable | The resource will not change while fresh at this URL. |
No-cache versus no-store
no-cache is a revalidation policy, not a storage ban. A cache can retain the response and ask the origin whether its validator still matches. The origin can answer 304 without sending the full body. no-store is appropriate when retaining the representation is unacceptable, such as highly sensitive personalized responses. It also prevents useful history and cache behavior, so do not apply it to public static assets without a reason.
Freshness and validators
max-age controls how long a stored response is fresh. After freshness expires, an ETag with If-None-Match or a Last-Modified value with If-Modified-Since can validate it. ETags are opaque validators; clients should return them unchanged. A 304 response reuses the stored representation and updates relevant metadata without transferring the normal body.
HTML and hash-named assets
Deployment entry HTML should normally revalidate so users discover new asset filenames promptly. A policy such as no-cache, must-revalidate permits efficient validators without serving an old application indefinitely. Hash-named JavaScript, CSS, fonts, and images can use a long max-age with immutable because any byte change creates a new URL. Never overwrite bytes behind an immutable URL.
Private and shared caches
Shared caches serve more than one user. Mark personalized authenticated responses private unless the application has a carefully designed shared-cache key and policy. Include a correct Vary field when representation selection depends on request headers such as Accept-Encoding or Origin. Avoid varying on high-cardinality fields unnecessarily because that fragments the cache.
Request directives and reloading
Clients can send request Cache-Control directives, but the resulting behavior also depends on the stored response and cache implementation. A browser reload is not a substitute for correct origin policy. Service workers add another cache layer with application-defined behavior; version and clean their caches, and do not let a cache-first navigation strategy pin old HTML.
Operational checks
Test headers on the actual canonical URL, redirects, HTML, assets, API responses, and error pages. Verify Age and cache-status fields where the platform supplies them. Deploy a changed asset and confirm old HTML revalidates while old hashed assets remain usable. Inspect copied response headers with the HTTP Header Analyzer.
Frequently Asked Questions
Does no-cache block storage?
No. It requires validation before reuse.
How do max-age and s-maxage differ?
s-maxage overrides freshness for shared caches.
When is immutable safe?
For URLs whose bytes never change, typically hash-named assets.