HTTP Caching
HTTP caching stores responses and reuses them until freshness expires, then revalidates with ETag or Last-Modified validators to save bandwidth and latency.
Definition
HTTP caching is the set of protocol rules, including Cache-Control, validators, and status codes, that let browsers, proxies, and CDNs reuse responses, revalidate stale copies, and serve content without contacting the origin.
Context and scope
Apply it to repeatable GET responses; the design question is how long each representation may be stale and which caches are allowed to store it.
Common misconceptions
- Caching is only a CDN concern; browsers and reverse proxies also cache, sometimes heuristically
- max-age guarantees freshness; clock skew, revalidation, and cached error responses complicate it
- no-store and no-cache are the same; no-store forbids storage while no-cache requires revalidation
Anti-patterns
- Caching authenticated responses in shared caches without private
- Using long max-age for content that changes without versioned URLs
- Relying on cache-busting query strings while ignoring Vary
Related concepts
Related examples
Authoritative source
How it works
A cache may store a response if the method is cacheable, usually GET or HEAD, and the response permits it. Freshness is computed from Cache-Control: max-age or s-maxage, or from Expires. While fresh, the cache serves the stored copy without contacting the origin.
HTTP/1.1 200 OK
Cache-Control: public, max-age=60, s-maxage=600, stale-while-revalidate=30
ETag: "v42"
Once stale, the cache revalidates with If-None-Match or If-Modified-Since. A 304 Not Modified refreshes freshness without a body; a 200 replaces the entry. private keeps responses out of shared caches, no-store forbids storage entirely, and immutable tells browsers not to revalidate.
When to use it
Use HTTP caching for static assets, public content, and API reads that tolerate short staleness. Versioned asset URLs can be cached for a year. Personalized or authenticated responses need private or no-store, and sensitive data must never land in a shared cache.
Trade-offs
Aggressive caching improves latency and origin load but makes updates visible late; invalidation by URL purge is not portable across caches. Long max-age without fingerprinting strands users on old content. Vary headers can explode cache keys. Conversely, no-cache everywhere wastes the protocol’s biggest performance lever. Measure hit ratio and origin latency before and after each policy change, because behavior differs between browsers, proxies, and CDNs.
Example and misconceptions
A classic production bug: an API returns user-specific JSON without Cache-Control: private, a CDN stores it, and the next user sees someone else’s data. The fix is explicit cache policy plus tests that inspect headers, not just response bodies.
Related concepts: Cache-Aside, Cache Invalidation, and Cache Stampede.