HTTP Caching and Status Codes
HTTP caching interacts with status codes in ways that have lasting consequences. A cached response that should not be cached causes stale data to be served; a response that should be cached but is not wastes bandwidth and increases server load. The HTTP specification in RFC 9110 defines which status codes are cacheable by default and which require explicit Cache-Control headers to enable caching.1 Knowing these defaults prevents costly surprises: a 404 response is cacheable by default, so caching a 404 without Cache-Control: no-store means a client may serve a stale "not found" page for a resource you subsequently create. This guide covers the caching semantics of the most operationally significant status codes, grounded in RFC 9110.
Which codes are cacheable by default under RFC 9110
RFC 9110 defines a specific set of status codes as cacheable by default, meaning a cache may store a response with that code even without explicit Cache-Control or Expires headers. The cacheable codes are: 200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414, and 501.1 These defaults matter because they determine how intermediaries (browser caches, reverse proxies, CDNs) handle responses without any explicit caching instructions from your server.
The 404 and 410 trap
404 and 410 are on this list, which often surprises developers who expect error responses to be uncacheable. A cached 404 can block a client from reaching a resource you create later at the same URL. Add Cache-Control: no-store to 404 and 410 responses for any URL that might be created in the future.
302 and 307 temporary redirects are not cacheable by default, which is consistent with their temporary semantics: the redirect target may change.2 500, 502, 503, and 504 are also not cacheable by default: error responses should not be served from cache because the server may recover at any time.
Cache-Control directives with status codes
Cache-Control directives override the default cacheability defined by RFC 9110 for any status code, giving you precise control over which intermediaries cache your responses and for how long. Cache-Control: no-store prevents any cache from storing the response. Cache-Control: no-cache allows the cache to store the response but requires revalidation before serving it. Cache-Control: max-age=N allows the cache to serve the stored response for N seconds without revalidating.3
Choosing between no-cache and max-age
The interaction between Cache-Control and status codes requires care: setting max-age=86400 on a 404 response causes caches to serve the "not found" response for 24 hours, blocking legitimate requests to a URL you recreate during that window. Setting no-store on a 200 response for a high-traffic public asset wastes bandwidth by forcing every request to the origin.
RFC 9110 defines which HTTP status codes are cacheable by default: 200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414, and 501. Define a Cache-Control strategy for each status code your API can return, not just for successful responses. Audit your error responses (4xx and 5xx) for unintended cacheability, and audit your responses that include user-specific or sensitive data for unintended public caching. A single misconfigured Cache-Control header on a high-traffic endpoint can cause stale content to be served to thousands of users or force unnecessary origin load that degrades performance for everyone.
The 304 conditional request flow
The 304 Not Modified response is the mechanism for cache revalidation: the cache uses it to verify that a stored response is still fresh without re-downloading the full body.4 When a cache stores a response with an ETag header, subsequent requests to the same URL include If-None-Match: "etag-value" in the request headers. The server compares the current ETag with the stored one and returns 304 (no body, headers updated) if the resource has not changed, or 200 (new body, new ETag) if it has.4
Implementing ETag generation in your application is the key prerequisite for 304 responses to work: without it, the server cannot confirm whether the cached response is still valid and must return 200 on every request. Strong ETags based on content hashes change whenever the resource body changes, while weak ETags based on version identifiers allow semantically equivalent updates to skip revalidation.
The Vary response header defines which request headers the cache must include in the cache key. Vary: Accept-Encoding ensures separate cached copies for compressed and uncompressed responses. Without the correct Vary header, caches may serve a compressed response to a client that does not support compression, or serve a cached response built for one authenticated user to a different authenticated user.5
CDN-specific cache directives and their interaction with Cache-Control
Standard Cache-Control headers apply to all caching intermediaries: browsers, reverse proxies, and CDNs. CDN-specific cache directives allow you to set different caching rules for the CDN layer without affecting the browser cache. Cloudflare uses CDN-Cache-Control to set CDN-only caching rules that Cloudflare respects and browsers ignore.6 Fastly uses Surrogate-Control, which Fastly strips before forwarding the response to the browser. This separation allows responses that browsers should not cache (personal account data with Cache-Control: private) to be cached at the CDN edge for performance without privacy implications.
Configuring CDN-specific directives enables different browser and edge cache durations. A product page might set Cache-Control: public, max-age=60 (60-second browser cache) alongside Surrogate-Control: max-age=3600 (one-hour Fastly cache). Fastly serves the cached version for one hour from the edge while browsers revalidate every 60 seconds. This hybrid strategy improves origin offload without serving stale browser-cached content for extended periods.
Cache invalidation via surrogate keys
Fastly and Cloudflare both support tagged cache invalidation through surrogate keys. Adding a Surrogate-Key: product-123 category-electronics header to a response tags that cached response with both keys. When product 123's data changes, send a purge request to the CDN targeting the product-123 key, and Cloudflare or Fastly invalidates all cached responses bearing that key immediately, across all edge locations.6 This allows precise cache invalidation without purging unrelated cached responses that happen to share the same cache path.
When to use this
Use this guide when designing the caching strategy for an API or website. Reference it to confirm which status codes are cacheable by default, to set the correct Cache-Control directives for each response type, and to implement 304-based cache revalidation.
Examples
GET /api/products — high-traffic read endpoint with data that changes hourly
Return 200 with Cache-Control: max-age=3600, must-revalidate and an ETag. Caches serve the response for up to one hour. After expiry, the conditional request returns 304 if the product data has not changed, saving a full re-download.
DELETE /api/products/123 — product removed, URL will not be recreated
Return 410 Gone with Cache-Control: max-age=86400. Caches serve the 410 for 24 hours, reducing server load from repeated requests to the deleted URL. Use 410 rather than 404 so search engines deindex the URL faster.
POST /api/orders — order creation endpoint
Return 201 Created with Cache-Control: no-store. POST responses should not be cached: each creation is a distinct operation with a new resource URL. The Location header points to the cacheable resource at its own URL.
- 1.
Roy Fielding, Mark Nottingham, and Julian Reschke, "HTTP Semantics," RFC 9110, IETF, June 2022. https://www.rfc-editor.org/rfc/rfc9110
- 2.
Stack Overflow, "Which HTTP status codes are cacheable?," stackoverflow.com, accessed June 2026. https://stackoverflow.com/questions/39398653/which-http-status-codes-are-cacheable
- 3.
Mozilla Developer Network, "Cache-Control," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
- 4.
Roy Fielding, Mark Nottingham, and Julian Reschke, "HTTP Caching," RFC 9111, IETF, June 2022. https://datatracker.ietf.org/doc/html/rfc9111
- 5.
Mozilla Developer Network, "Vary," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary
- 6.
Cloudflare, "CDN-Cache-Control," developers.cloudflare.com, accessed June 2026. https://developers.cloudflare.com/cache/concepts/cdn-cache-control/