Why one URL can have two cache entries
· sitewarm
Two requests for the same address can end up as two separate entries in a CDN cache. The reason is the cache key: the cache stores and finds responses by it, and the address is only part of it. This article explains what makes up a cache key according to the standards and to Amazon CloudFront's documentation, and how Vary, headers, cookies and query strings change it.
Everything here comes from RFC 9110, RFC 9111, MDN and the CloudFront documentation, read on 2026-10-24. Other CDNs have their own rules, which this article does not describe. The example requests are illustrative, not captured from a real site.
What a cache key is
RFC 9111 says the key a cache uses to find a stored response is composed "at a minimum" of the request method and the target URI used to retrieve it. The words "at a minimum" matter: caches may add more to the key, and the standards describe one way to do it, the Vary header, in the next section.
CloudFront words the same idea from the CDN side. The cache key is "the unique identifier for every object in the cache", and it determines whether a viewer's request results in a cache hit. A hit occurs when a request generates the same cache key as a prior request and the object for that key is in the edge location's cache and valid. See cache key.
Because the key starts with the target URI, a request for a different URI is a different entry. That is a reading of the RFC's wording, and a CDN can be configured to treat parts of the URI differently, as the query string section below shows.
Vary: the response adds to the key
RFC 9110 defines Vary as a response header that describes what parts of a request, aside from the method and target URI, might have influenced the origin server's choice of content. Its example is Vary: accept-encoding, accept-language, which indicates that the origin might have used those two request headers when choosing the content.
For caches, the RFC states the effect directly. A cache must not use the response to satisfy a later request unless the later request has the same values for the listed headers as the original request, or the origin has validated the reuse. In the RFC's words: "Vary expands the cache key required to match a new request to the stored cache entry." MDN says the same in its own terms: Vary ensures that responses are separately cached based on the headers it lists, most often when content negotiation is in use. See Vary.
- Header values are compared after normalization when it is known to preserve their meaning. RFC 9111 allows normalizing both header values in a way known to have identical semantics before deciding whether they match.
- A
Varyvalue that includes*never matches. RFC 9111 says such a stored response "always fails to match", and MDN says it implies the response is uncacheable. RFC 9110 explains the wildcard as a signal that other aspects of the request, possibly outside the message syntax, played a role. Varyis optional. RFC 9110 says it might be left out when the origin considers variance in content selection to be less significant thanVary's performance impact on caching.
Headers, cookies and query strings at a CDN
A CDN can also build its key from more than the standards require, and it often lets you choose. CloudFront's cache policy specifies the HTTP headers, cookies and query strings that CloudFront includes in the cache key. Each one you add can split a single page into several entries, because two requests that differ in an included value produce different keys.
CloudFront states the consequence plainly: including fewer values in the cache key increases the likelihood of a cache hit, and gives a higher cache hit ratio, which it defines here as a higher proportion of viewer requests that result in a cache hit. The reverse follows from the same sentence: more values in the key leaves fewer requests with a matching entry.
The RFC sections read for this article do not give cookies or query strings a special role. Whether a cookie or a query parameter is part of the key is a CDN setting, so read your CDN's documentation for it.
A worked example
These requests are illustrative and not captured from a real site. Suppose a page responds with Vary: accept-language, and three requests arrive for the same path:
| Request | What differs | Entry it uses |
|---|---|---|
| A | Accept-Language: en | Entry 1 |
| B | Accept-Language: es | Entry 2, because the listed header has a different value |
| C | Accept-Language: en, and a tracking parameter added to the address | Entry 3 if the query string is part of the key, or Entry 1 if the CDN is set to leave it out |
One address, up to three entries. Each entry has its own hit or miss, so a request that finds no entry with the same key is a miss even though the page is cached for another key.
What this does not tell you
- It does not say which headers, cookies or query strings your CDN includes by default. Read its documentation.
- A cache hit for one key says nothing about the other keys of the same address. Request the page again with the variation you care about, such as another language or encoding.
Where sitewarm fits
sitewarm requests pages from your sitemap, up to the scan's URL limit, and reports the cache state the CDN returns for each one, with the vantage point it was measured from.
Frequently asked questions
What is in a cache key?
RFC 9111 says it is composed, at a minimum, of the request method and the target URI. Caches may add more, and Vary is the standard way for a response to ask for more. CDNs such as CloudFront also let you add headers, cookies and query strings. See cache key.
What does Vary do in a cache?
RFC 9110 says a cache must not use a stored response for a later request unless the request has the same values for the headers listed in Vary, or the reuse has been validated by the origin. In its words, Vary expands the cache key. See Vary.
Why would the same URL be cached twice?
Because something other than the URL differs between the requests and is part of the key: a header listed in Vary, or a header, cookie or query string that the CDN is set to include.
Does Vary: * make a response uncacheable?
RFC 9111 says a stored response with * in Vary always fails to match a new request, and MDN says it implies the response is uncacheable.
References
- RFC 9110: HTTP Semanticshttps://www.rfc-editor.org/rfc/rfc9110
- RFC 9111: HTTP Cachinghttps://www.rfc-editor.org/rfc/rfc9111
- MDN: Varyhttps://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Vary
- Amazon CloudFront: Control the cache key with a policyhttps://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html
See the cache state your CDN returns for each page
sitewarm requests pages from your sitemap, up to the scan's URL limit, after a deploy and reports the cache state the CDN returns for each one, with the vantage point it was measured from.