The cache key identifies a cached object. Two requests with the same key get the same cached response.
What's in the key
| Part | How it's normalized |
|---|---|
| Site | Each proxied name is its own site, so names never share objects. |
| Host | Lower case, without port or trailing dot. |
| Path | %XX escapes in upper case, escapes of unreserved characters decoded, . and .. segments resolved. // is kept and reserved characters stay as sent (%2F and / are different). The same path is sent to the origin. |
| Query string | According to the caching level. |
| Variant | Only when the origin sends a supported Vary. |
Cookies, the Authorization header and the OpenWAF challenge and access-gate cookies never enter the key. Keys longer than 4 KB aren't cached.
Changing the query settings of a site or its rules changes its keys, which acts like a purge for that site.
Query string
cache.query.mode, called Caching level in the dashboard, decides which part of the query string goes into the key:
| Mode | Dashboard | Key |
|---|---|---|
all (default) | Standard: the whole query string | The whole query, exactly as sent. ?v=1 and ?v=2 are different objects. |
ignore | Ignore query string (static files) | No query, but only for the default static extensions. Rule-eligible paths keep their query. |
none | No query string: cache only requests without one | Requests with a query aren't cached at all (DYNAMIC). |
include | Only these parameters | Only the parameters in cache.query.params. |
exclude | All parameters except these | Every parameter except those in cache.query.params, for example utm_*, fbclid, gclid. |
A trailing * in params matches a prefix. With cache.query.sort set to true, the parameters are sorted, so ?b=1&a=2 and ?a=2&b=1 share one object. A cache rule can set its own query policy for the requests it matches.
Vary
The edge stores at most one variant per value of the supported Vary headers:
Vary header | Handling |
|---|---|
Accept-Encoding | Doesn't split the cache: one copy, decompressed on the fly for visitors who need it. |
Accept | Only for image/* responses. Normalized to avif, webp or other, enough for image optimizers. |
Origin | Normalized to scheme://host[:port]. Also applied when the response has an Access-Control-Allow-Origin other than *, even without Vary: Origin, so one site's CORS answer is never served to another. |
Anything else, including *, Cookie and Authorization | The response isn't stored (BYPASS). |
A cache rule can list request headers in vary_bypass_if_present (for example the RSC and Next-Router-* headers of Next.js). A request carrying any of them skips the cache, and a Vary from the origin that names them no longer prevents storing the normal version. See Cache rules.
Headers removed before the origin
On eligible requests the edge removes headers that aren't in the key but that an origin might reflect into the page, a common cache-poisoning vector:
X-Original-URL, X-Rewrite-URL, X-HTTP-Method-Override, X-HTTP-Method, X-Method-Override, X-Host, X-Forwarded-Scheme, X-Forwarded-Server and X-Forwarded-Port.