Field guide · updated 20 Sep 2026
HTTP Cache Field Guide
Choose cache headers that fit the response—and diagnose “old content” without accidentally sharing private data.
The short answer
Separate storage audience, freshness, and matching. Use private, no-cache when a personalized response may stay in a browser but must not enter a shared cache; use no-store when compliant HTTP caches should not intentionally retain it. Add validators for cheap revalidation. When both conditional validators are sent, If-None-Match wins.
Four decisions before shipping a cacheable response
| Decision | Question | Useful starting point |
|---|---|---|
| 1 · Audience | Private or safely shared? Cookies and authentication can make the body user-specific. | Decide the audience before adding public or s-maxage. |
| 2 · Lifetime | How long is fresh? | Set explicit max-age; shared caches may use a separate s-maxage. |
| 3 · Validation | How does stale content recover? | With both validators, If-None-Match is evaluated before If-Modified-Since. |
| 4 · Variants | What changes the body? | Keep target URI, Vary-nominated fields, cookies, authorization, and unlisted application inputs from creating a privacy mismatch. |
Pick a response class
| Response class | Starting policy | Guardrail |
|---|---|---|
| Personalized | private, no-cache | A browser may retain a copy; a shared cache must not. Use no-store when intentional HTTP-cache retention is unacceptable. |
| Public dynamic | public, max-age=60, s-maxage=10 | Only when the representation is safe to share and request variants are accounted for. |
| Versioned asset | public, max-age=31536000, immutable | Fingerprint the URL and deploy a new URL for changed bytes. |
| Must not store | no-store | Compliant caches should not intentionally store or use it; it does not erase an older entry or encrypt the network. |
Locate the serving layer
An old response may come from history/bfcache, a service worker/Cache API, the browser HTTP cache, an intermediary, or the origin. Start by asking whether a new fetch happened; then seek positive, named evidence rather than inferring from 200, a DevTools label, or a missing header.
Open the serving-layer diagnosis guide → · Read the dated report
Cloudflare Cache Rules and Origin Cache Control
Cloudflare adds product-specific controls around ordinary HTTP semantics: Origin Cache Control, the matching Cache Rule's Edge Cache TTL, Browser TTL, cache-key dimensions, and purge scope must be read separately.
Documentation-only: no zone, authorized response, or purge was available. Open the Cloudflare guide page · Read the dated report →
CloudFront TTL policy and invalidation
For a named CloudFront behavior, inspect the effective minimum/default/maximum TTLs and cache key. A positive minimum can override origin no-store, private, or no-cache; the audit also narrows the standalone s-maxage documentation gap and keeps viewer headers separate from edge evidence.
Documentation-only: no distribution, cache capture, or invalidation was run. Open the CloudFront guide page · Read the audit refresh →
Use the cache freshness calculator
Need to compare a browser max-age with a shared-cache s-maxage? Open the Cache-Control freshness calculator → for the interactive inputs, formula, browser/CDN explanation, worked examples, FAQ, and limits.
It is a teaching calculation for supplied lifetime and age values—not a complete RFC 9111 current-age calculation, a security boundary, or a vendor configuration test. The original sandboxed tool remains at the existing tool URL.