Utopia Tech
Engineering4 min read

We just shipped support for the ugliest part of HTTP: Vary

The response header, Vary , has been called “ the ugliest part of HTTP that we haven't yet improved. ” The same post describes it as a “horrible, kludgy mechanism” with “pretty abysmal interoperability” across intermediaries. That is usually where sensible engineers back away slowly with their hands raised. That’s not exactly an endorsement of Vary , but ugly doesn’t mean usele

UT

Utopia Tech

September 22, 2026 · 4 min read

Share

The response header, Vary , has been called “ the ugliest part of HTTP that we haven't yet improved. ” The same post describes it as a “horrible, kludgy mechanism” with “pretty abysmal interoperability” across intermediaries. That is usually where sensible engineers back away slowly with their hands raised.

That’s not exactly an endorsement of Vary , but ugly doesn’t mean useless. One URL can have more than one correct response. A server might, for example, deliver different image formats to different browsers.

If a cache ignores Vary , it risks serving the wrong bytes to a request. But if it treats every raw header value as distinct, a handful of similar requests can spread into thousands of barely reusable cache entries. Vary tells a cache which request fields may affect the response, but it does not tell the cache which differences actually matter.

Vary support is now available in Cache Rules on every plan. The origin still names the request headers that may affect a response, but you decide how Cloudflare handles each one. You can normalize known negotiation headers, pass exact values through when those small differences matter, or bypass cache when the variation is too unpredictable.

The origin declares what may vary, and you decide how much variation is actually meaningful for the cache. How Vary works Vary is a standard HTTP response header that tells intermediary caches (like Cloudflare) which request fields may affect the response sent by the origin. Sites use Vary to serve different languages, image formats, compression schemes, or regional content from the same URL.

Take one URL that produces two valid representations. A browser requests a webpage: The origin returns HTML and identifies Accept as a field that may affect the response: An API client can request the same URL with a different preference: This time, the correct response is JSON. The Vary: Accept header tells the cache that the URL alone is not enough to choose between responses.

The request’s Accept value must also be considered. Without Vary , whichever response enters the cache first can be served to both clients. If HTML wins, the API client receives markup and its JSON parser fails.

If JSON wins, a browser expecting a web page receives an API response. Vary prevents the cache from serving the wrong response to the requesting client. But it introduces a harder question: when two requests contain different header values, do they actually need different responses?

When correct caching becomes useless Vary can tell a cache which request fields may affect a response. It does not tell the cache what the response represents. For example, take an origin that serves content in only English, French, and German.

A client might send: While another client might request: Both requests prefer English here. The origin’s response may map both requests to exactly the same English response. But a cache comparing the raw values cannot safely assume they are equivalent.

They have different orders and language tags (that the origin doesn’t differentiate). So the cache may store them as separate variants, even when their response bodies contain identical bytes. This is Vary ’s central problem.

Applications often produce a small, finite set of representations from an enormous set of possible request values. The origin understands that thousands of language preferences collapse into three supported languages, while a cache usually does not. This problem compounds when a response varies on multiple fields.

Ten possible values across one field create ten variants. Ten values across three fields can create 1,000 combinations. Real headers can have far greater cardinality: User-Agent values are numerous, cookies can be unique to individual visitors, and preference headers can differ in ordering, formatting (spaces and tabs matter!)

, and quality values . The result is a cache that can be perfectly correct and almost permanently cold (an entry never reused). Identical responses can be scattered across entries that receive too little traffic to remain hot and in cache.

They can consume capacity, evict one another, reduce cache hit ratios, and send more requests back to origin servers. Eviction can remove cold entries, but it cannot merge them just because the responses are identical. An analysis of more than 120 million responses from nearly 50,000 popular sites found almost 3,000 sites varying on four or more fields.

Some varied on 10, 23, or even 47 fields. We want to make sure that customers have the tools they need to use Vary when appropriate, but not so much that they create a useless cache. Some high-cardinality variation is deliberate.

CDNs or reverse proxies may inject values, such as a geographic region, to partition content predictably. That works when the possible values are controlled and every component agrees on their meaning. Without those constraints, the cache fragments into variants it may never reuse.

That was the design problem we needed to solve to support Vary . We needed to preserve enough variation to serve the right response, without allowing incidental differences between requests to destroy cache efficiency. How Cache Rules control Vary Cloudflare customers already had several ways to handle negotiated content similar to Vary .

They could bypass cache and let their origin deal with it, reproduce the origin's negotiation logic in a custom cache key or other rule , use a Worker , or use features like Vary for images . Those options remain useful, but they either give up caching, duplicate application logic, need to write additional code, or address a narrower use case. Vary in Cache Rules may fill the gap between these existing features by splitting support into two decisions: The origin uses Vary to identify the request headers that may affect a response.

The Cache Rule determines how Cloudflare handles the value of each header. A Cache Rule does not force every response to vary .

Originally published at blog.cloudflare.com

Share
▸ Want a deeper look?

Talk to an architect about applying this to your stack.

60-minute technical evaluation, no obligation. We'll map the ideas in this article to your environment.

Skip to main content