The Core Problem: Why Request-Time Caching Rules Fall Short
A Content Delivery Network (CDN) cache and an origin server operate as a tightly coupled pair. To maximize performance and minimize origin infrastructure costs, the edge must answer requests from cache whenever possible. However, the origin server acts as the ultimate guide for the cache. Through response headers, the origin dictates how long an asset can be served, how it should be revalidated, and whether it is eligible for caching at all.
When the origin gets these directives wrong, caching efficiency plummets. A common manifestation of this issue is the accidental inclusion of a Set-Cookie header on static assets, or the delivery of a Cache-Control: no-cache directive on files that are entirely safe to cache. Historically, resolving these issues required modifying the origin application code, deploying custom Cloudflare Workers to intercept and rewrite responses, or simply accepting a lower cache hit ratio.
None of these issues can be resolved during the request phase. By the time Cloudflare detects a cache-breaking header on an incoming asset, the request phase has already concluded. To address this architectural gap, Cloudflare introduced Cache Response Rules, which execute after the origin server replies but before the response is written to the edge cache.
Understanding the Two-Phase Caching Architecture
To implement caching strategies effectively, it is essential to distinguish between the two distinct phases of Cloudflare’s caching pipeline:
- The Request Phase (Cache Rules): Running before Cloudflare contacts the origin, Cache Rules determine whether Cloudflare should look up an asset in the cache, and what cache key to use. This phase handles cache eligibility (eligible vs. bypass), cache key customization, and initial TTL configurations.
- The Response Phase (Cache Response Rules): Running after the origin replies but before the response is written to the cache, Cache Response Rules allow you to adjust caching behavior based on the actual response headers returned by the origin.
When a Cache Rule and a Cache Response Rule conflict, the Cache Response Rule wins. However, the response phase cannot alter decisions that were locked during the request phase. For example, a Cache Response Rule cannot change the cache key, nor can it force Cloudflare to cache a request that was explicitly bypassed during the request phase.
Action 1: Stripping Cache-Breaking Headers
The set_cache_settings action allows you to strip headers that prevent caching directly from the origin response. This action supports three boolean parameters:
{
"action_parameters": {
"strip_etags": true,
"strip_set_cookie": true,
"strip_last_modified": true
}
}
Stripping Set-Cookie is highly effective for resolving issues where application frameworks or load balancers attach session cookies to static assets. By stripping this header in the response phase, the assets become cacheable at the edge without requiring upstream modifications.
Notably, Cache Response Rules also execute on responses that are not eligible for caching. If you strip Set-Cookie from a dynamic response, the rule still fires, ensuring that the client does not receive the cookie even if the response is never written to the cache.
If you choose to strip both ETag and Last-Modified, Cloudflare enables Smart Edge Revalidation for that response. However, if your Cache Response Rules subsequently append new validators, Cloudflare will not enable Smart Edge Revalidation for browser conditional requests.
Action 2: Granular Cache-Control Overrides
The set_cache_control action provides precise control over the directives that dictate how both Cloudflare and downstream clients cache assets. Supported directives include:
- Duration Directives:
max-age,s-maxage,stale-if-error,stale-while-revalidate - Qualified Directives:
private,no-cache(with optional header-name qualifiers) - Boolean Directives:
no-store,no-transform,must-revalidate,proxy-revalidate,must-understand,public,immutable
A key feature of this action is the cloudflare_only parameter. When set to true, the directive modifies how Cloudflare caches the asset, but the original header sent downstream to the browser remains unchanged:
{
"action_parameters": {
"s-maxage": {
"operation": "set",
"value": 86400,
"cloudflare_only": true
}
}
}
This allows you to maintain a long cache lifetime at the edge while enforcing a shorter cache lifetime or different revalidation rules for the end-user’s browser.
Action 3: Dynamic Cache Tag Management
The set_cache_tags action enables you to add, remove, or set cache tags on a response, which are used for purging content by tag. Tags can be defined statically or computed dynamically from response headers using expressions:
{
"action_parameters": {
"operation": "add",
"expression": "split(http.response.headers["Surrogate-Keys"][0], ",", 64)"
}
}
This is particularly useful during CDN migrations. If your legacy CDN used a header like Surrogate-Keys with comma-separated values, you can parse and map those values directly to Cloudflare’s Cache-Tag format. The third argument in the split() function defines the maximum number of elements in the resulting array (accepting a value between 1 and 128). Setting this limit to 1 would treat the entire header value as a single tag.
Practical Implementation Examples
Example 1: Strip Set-Cookie from Static Asset Extensions
To prevent session cookies from breaking the cache on static assets, target specific file extensions and strip the Set-Cookie header.
- Expression:
http.request.uri.path.extension in {"js" "css" "woff2" "woff" "ttf" "png" "jpg" "svg"} - Action:
set_cache_settings - Parameters:
strip_set_cookie: true
Caveat: Only apply this rule to file types where cookies are not semantically required for dynamic content variation.
Example 2: Decouple Edge and Browser Cache Lifetimes
Cache static assets for 30 days on Cloudflare’s edge while instructing browsers to revalidate after 24 hours.
- Expression:
http.request.uri.path.extension in {"js" "css" "woff2"} - Action:
set_cache_control - Parameters:
s-maxage: set to2592000(30 days),cloudflare_only: trueimmutable: set totruemax-age: set to86400(1 day),cloudflare_only: false
Caveat: Because immutable instructs browsers not to revalidate even on page refresh, only pair this configuration with versioned or hashed filenames.
Example 3: Override no-cache on Known-Static Paths
Override restrictive origin framework defaults that append no-cache to safe, static directories.
- Expression:
starts_with(http.request.uri.path, "/static/") and http.response.code eq 200 - Action:
set_cache_control - Parameters:
no-cache: removes-maxage: set to3600,cloudflare_only: true
Caveat: Ensure that no user-specific or dynamic content is served from the targeted path before overriding no-cache.
API Integration and Execution Flow
Cache Response Rules can be managed programmatically via the Cloudflare API. Rules in this phase are deployed to the following entrypoint:
/zones/{zone_id}/rulesets/phases/http_response_cache_settings/entrypoint
The execution flow proceeds as follows:
- An incoming request is evaluated against Cache Rules (Request Phase).
- If a cache miss occurs, Cloudflare fetches the asset from the origin server.
- The origin responds, and Cloudflare evaluates the response against Cache Response Rules (Response Phase).
- The modified headers are applied, and the asset is written to the Cloudflare edge cache according to the updated directives.
Limitations and Architectural Constraints
While Cache Response Rules offer powerful capabilities, developers must design rules within the following constraints:
- No Cache Key Modification: The cache key is fixed during the request phase. Cache Response Rules cannot alter how an object is identified in the cache.
- No Forced Caching of Bypassed Requests: If a request is marked as “Bypass” during the request phase (via Cache Rules or Page Rules), a Cache Response Rule cannot force it to be cached.
- Split Function Limits: When parsing headers for cache tags, the limit parameter of the
split()function must be an integer between 1 and 128. - Revalidation Tradeoffs: Stripping validator headers (
ETagandLast-Modified) changes how conditional requests are handled. Ensure downstream clients do not rely on these specific validators if they are stripped at the edge.
Frequently asked questions
Can Cache Response Rules make a bypassed request cacheable?
No. If a request is set to bypass cache during the request phase (using Cache Rules or Page Rules), a Cache Response Rule cannot override that decision to make the asset cacheable.
What is the purpose of the cloudflare_only parameter in Cache-Control directives?
When cloudflare_only is set to true, the Cache-Control directive only applies to Cloudflare's edge cache. The original header value sent downstream to the browser remains unmodified.
How does stripping ETag and Last-Modified headers affect revalidation?
Stripping both headers enables Smart Edge Revalidation for that response. However, if you use Cache Response Rules to add new validators, Cloudflare will not enable Smart Edge Revalidation for browser conditional requests.
What is the limit for the split() function when generating dynamic cache tags?
The third argument of the split() function, which specifies the maximum number of elements in the resulting array, must be an integer between 1 and 128.
Primary reference: Review the original announcement for exact release details. This article is an independent explanation and does not reproduce the source text.
