Learn how Cloudflare interprets Cache-Control headers from customer origins when the Origin Cache Control feature is enabled via a Cloudflare Page Rule.
Cache-Control headers are one way administrators can tell Cloudflare how to handle content your origin serves. There are two parts to how Cloudflare makes caching decisions: a request phase and a response phase.
In the request phase, the URL the client requests is matched against a list of cacheable file extensions. If the request matches an extension on this list, Cloudflare serves the content from cache if present. If the content is stale in Cloudflare's cache, Cloudflare attempts to revalidate the content with the origin before serving the response to the client.
It is possible to modify what Cloudflare deems cacheable via the Cache Level setting in Cloudflare's Page Rule app. As an example, Cache Everything causes the extension check to be skipped, and all content will be treated as cacheable. Refer to Cloudflare's guide on how to use the Cache Everything setting.
If Cloudflare deems a request cacheable, we first examine our caches in multiple network locations for content. If the resource is not present in cache, Cloudflare will make a request to the origin to fill our cache. The response is then sent to the client who initiated the request.
At this point, our cache logic examines the HTTP response received from the origin server.
Based on its interpretation of the headers in the request, the response will either be deemed cacheable and written to disk (to be used for the next request for the object), or deemed uncacheable (resulting in the next request missing cache and repeating this flow).
The Cache-Control header can include a number of directives. If multiple directives are passed together, each is separated by a comma. If the directive takes an argument, it follows the directive separated by an equals sign.
Broadly, the directives break down into broad buckets around cacheability (should this object enter a cache?), expiration (how long should it stay in cache?), revalidation (how should the cache behave when an object has “expired”?) and a few others that control how caches should handle content.
The "public" response directive indicates that any cache MAY store the response, even if the response would normally be non-cacheable or cacheable only within a private cache.
The "private" response directive indicates that the response message is intended for a single user (eg. a browser cache) and MUST NOT be stored by a shared cache (like Cloudflare, or a corporate proxy).
The "no-store" response directive indicates that any cache (ie a client or proxy cache) MUST NOT store any part of either the immediate request or response.
The "max-age" response directive indicates that the response is to be considered stale after its age is greater than the specified number of seconds. Age is defined as the time in seconds since the asset was served from the origin. The seconds argument is an unquoted integer.
The "s-maxage" response directive indicates that, in shared caches, the maximum age specified by this directive overrides the maximum age specified by either the max-age directive or the Expires header field. The s-maxage directive also implies the semantics of the proxy-revalidate response directive.
The "no-cache" response directive indicates that the response MUST NOT be used to satisfy a subsequent request without successful validation on the origin server. This allows an origin server to prevent a cache from using it to satisfy a request without contacting it, even by caches that have been configured to send stale responses.
The "must-revalidate" response directive indicates that once it has become stale, a cache (client or proxy) MUST NOT use the response to satisfy subsequent requests without successful validation on the origin server.
The "proxy-revalidate" response directive has the same meaning as the must-revalidate response directive, except that it does not apply to private client caches.
When present in an HTTP response, the stale-while-revalidate Cache-Control extension indicates that caches MAY serve the response in which it appears after it becomes stale, up to the indicated number of seconds since the object expired. Note: If Always Online is enabled, then the stale-while-revalidate directive will be ignored.
The stale-if-error Cache-Control extension indicates that when an error is encountered, a cached stale response MAY be used to satisfy the request, regardless of other freshness information. Note: If Always Online is enabled, then the stale-if-error directive will be ignored.
The "no-transform" response directive indicates that an intermediary (regardless of whether it implements a cache) MUST NOT transform the payload
Indicates to clients that the response body will not change over time. The resource, if unexpired, is unchanged on the server and therefore the client should not send a conditional revalidation for it (e.g. If-None-Match or If-Modified-Since) to check for updates, even when the user explicitly refreshes the page. This directive has no effect on public caches like Cloudflare, but does change browser behavior.
Cache a static asset
Cache-Control: public, max-age=86400
Make sure a secret asset is never cached
Allow an asset to be cached on browsers, but not on proxy caches
Cache-Control: private, max-age=3600
Allow an asset to be cached in client and proxy caches, but prefer revalidation each time the asset is served
Cache-Control: public, no-cache
Allow an asset to be cached in proxy caches, but REQUIRE revalidation by the proxy each time the asset is served
Cache-Control: public, no-cache, proxy-revalidate
Cache-Control: public, s-maxage=0
Allow an asset to be cached in proxy caches, but REQUIRE revalidation by any cache each time the asset is served
Cache-Control: public, no-cache, must-revalidate
Allow an asset to be cached, but make sure the proxy does not modify it
Cache-Control: public, no-transform
Note this will also disable transformation like gzip or brotli compression from our edge to your visitors if the original payload was served uncompressed.
Allow an asset to be cached, prefer revalidation, but allow stale responses to be served if the origin server is unreachable or serving errors
Cache-Control: public, max-age=3600, stale-if-error=60
Cloudflare will attempt to revalidate the content with the origin after it has been in cache for 3600 seconds (1 hour). If the server is returning an error instead of proper revalidation responses, Cloudflare will continue serving the stale resource for a total of 1 minute beyond the expiration of the resource.
Cache an asset for different amounts of time on Cloudflare and in a visitor’s browser
Cache-Control: public, max-age=7200, s-maxage=3600
Cache an asset and serve the asset while it is being revalidated
Cache-Control: max-age=600, stale-while-revalidate=30
Indicates that it is fresh for 600 seconds, and it may continue to be served stale for up to an additional 30 seconds to parallel requests for the same resource while the initial synchronous revalidation is attempted.
Interaction with other Cloudflare features
Edge Cache TTL
Edge Cache TTL page rule settings override s-maxage and disable revalidation directives if present. The original Cache-Control header is passed downstream from our edge even if Edge Cache TTL overrides are present.
Browser Cache TTL
Browser Cache TTL page rules settings override max-age settings passed downstream from our edge, typically to your visitor's browsers.
Polish is disabled when the no-transform directive is present.
Gzip and Other Compression
Compression is disabled when the no-transform directive is present. If the original asset fetched from the origin is compressed, this will be served compressed to the visitor. If the original asset is uncompressed, compression will not be applied.