Cloudflare Finally Supports HTTP Vary Header: The Content Negotiation Caching Puzzle Solved

Cloudflare adds full HTTP Vary header support, fixing edge cache content negotiation — but explicit URL suffixes may still be simpler.
Cloudflare has announced full support for the HTTP Vary header, which previously only applied to image assets. The Vary header is central to HTTP content negotiation, telling caches that the same URL may return different responses based on headers like Accept or Accept-Language. Without proper Vary support, CDNs risk serving cached JSON to users expecting HTML — a classic cache poisoning problem. Implementation is hard because caches must maintain multiple variants per URL, and high-cardinality fields like User-Agent can destroy cache efficiency entirely. Notably, Simon Willison — who had long awaited this feature — says he now prefers explicit .json URL suffixes over header-based negotiation for better predictability and cacheability.
The Thorniest Part of HTTP Is Finally Tamed
Cloudflare recently announced support for the HTTP Vary header — a feature developers have long called "the ugliest part" of the protocol. The change may seem minor, but it resolves a caching headache that has plagued developers for years. Prominent developer Simon Willison said in a Hacker News discussion that he had "wanted Cloudflare to implement this for years."
The Vary header sits at the heart of HTTP content negotiation. It tells caching servers that responses for the same URL may differ depending on request headers such as Accept, Accept-Encoding, or Accept-Language. Understanding why it matters requires understanding the problem it was designed to solve.
The Classic Clash Between Content Negotiation and Caching
Consider a typical scenario: when a user agent sends Accept: text/html, the server returns an HTML page; when a client requests a different format, the server returns JSON or another data type. This kind of header-driven content negotiation is a common pattern for building services that serve both flexible APIs and web pages from the same endpoints.
The trouble begins when an edge cache enters the picture. Simon Willison noted that this pattern was previously "impossible to deploy behind Cloudflare's cache." The reason is straightforward — Cloudflare previously respected Vary only for image assets, ignoring it for all other response types.
The consequences were predictable: a cache might store the JSON version of a response, then serve that same JSON to a user who clearly expected HTML. Same URL, wrong content type cached, page completely broken. This is exactly why Vary earned its reputation as HTTP's "ugliest part" — the concept is simple, but getting the implementation right is surprisingly hard.

HTTP Content Negotiation is a mechanism defined in the HTTP/1.1 specification that allows a server to return different representations of the same resource based on client capabilities or preferences. The most common negotiation dimensions are: Accept (content format, e.g., HTML/JSON/XML), Accept-Encoding (compression method, e.g., gzip/br), Accept-Language (language preference, e.g., zh-CN/en-US), and Accept-Charset (character set). When a server dynamically adjusts its response based on these request headers, it must include a corresponding Vary header in the response, telling downstream caches which request header differences will produce different response content. Without the Vary header, caching servers have no way to know which request dimensions the response depends on, making it easy to incorrectly serve a response targeted at one client type to a completely different type of requester — a phenomenon known as "cache poisoning." This mechanism is logically clean in single-server scenarios, but its complexity increases dramatically when implemented across CDN distributed cache layers.
Why Supporting Vary Is So Hard
The complexity of implementing Vary stems from the requirement that a caching system maintain multiple variant versions of the same URL. A cache can no longer use the URL alone as a cache key; it must combine the URL with the values of the request headers listed in Vary to generate a composite cache key.
For a CDN operating across hundreds of nodes worldwide, this means cache hit logic, storage overhead, and consistency maintenance all multiply significantly. When a Vary header references a high-cardinality field like User-Agent, cache effectiveness can be completely destroyed — every slightly different browser identifier generates a new variant. This is the technical reason many CDNs have long chosen to selectively ignore Vary headers.
With Cloudflare's full Vary support, developers can finally confidently deploy content negotiation at the edge cache layer without worrying about cache poisoning.
"High Cardinality" is the key concept for understanding why the Vary header can be dangerous. Cardinality refers to the number of possible values a given field can take. Accept-Language has a limited set of common values (dozens of language combinations), making it a low-cardinality field with manageable impact on caching. But User-Agent strings exhibit millions of distinct values due to combinations of browser versions, operating systems, and device models — making it an extremely high-cardinality field. Once Vary: User-Agent appears, the caching system effectively needs to store a separate response copy for every unique browser identifier, driving cache hit rates toward zero and turning the CDN into little more than a transparent proxy. For this reason, the HTTP specification recommends that Vary headers list only the minimum set of headers that truly affect the response content, and that low-cardinality fields be preferred. Many CDNs, to protect the stability of their own infrastructure, choose to reject or ignore Vary headers containing high-cardinality fields — or abandon Vary support altogether.
A Different Trade-Off in Practice
Interestingly, despite having waited years for this feature, Simon Willison has already decided to stop using content negotiation based on the Accept header himself.
His reasoning is worth considering for any API designer: he prefers "URLs that predictably return HTML or JSON." His specific approach is to add a .json suffix to URLs in his applications to explicitly request JSON data, rather than relying on request headers to implicitly switch formats.
This design philosophy and content negotiation represent two distinct ways of thinking:
- Content Negotiation (Vary-dependent): A single URL serves multiple representations, differentiated by request headers. Semantically more aligned with REST principles, but unfriendly to caching and debugging.
- Explicit URL Suffixes:
/datareturns HTML,/data.jsonreturns JSON. URLs map one-to-one with content, making behavior predictable, easy to cache, and simple to debug and share.
The latter sacrifices some HTTP semantic purity in exchange for engineering certainty. This also explains why, even now that Cloudflare has filled the Vary gap, many developers will continue choosing the simpler suffix-based approach.
What This Means for Developers
This update opens new possibilities for teams that need content negotiation. Applications that already rely on Accept headers to return different formats — and want to take advantage of Cloudflare edge caching — can now combine the two more safely.
But the deeper takeaway is this: filling a capability gap doesn't automatically make a design approach optimal. The Vary header is finally usable, but whether to use it still comes down to how you balance predictability, cacheability, and API semantics. For most projects that prioritize simplicity and certainty, an explicit URL convention may still be the safer choice.
Regardless, HTTP's "ugliest part" has finally received proper treatment from a mainstream CDN — and that alone is a positive signal of infrastructure maturity.
Related articles

AI-Powered SRC Vulnerability Hunting: A Hands-On Guide to Building the Hermes Agent Workbench
Based on a hands-on Bilibili video: how to build an AI-powered SRC vulnerability hunting workbench—three-step method, four report elements, Agent mode vs web chat, and tool selection.

CLI-Anything Complete Beginner's Guide: How AI Operates Software — Principles and Practice
A complete beginner's guide to CLI-Anything: how AI Agents operate professional software via the command line, covering the three-layer architecture, CLI Hub installation, DrawIO practice, generator principles, and limits.

Carbon-X: A 14.8B Open-Source Model That Handles DNA and Text Simultaneously
Carbon-X is a 14.8B open-source multimodal model on Hugging Face where DNA and text share a token stream. 6-mer tokenization, 302B token mid-training, deployable on a single 80GB GPU, 66.7% average on five DNA benchmarks, Apache 2.0 license.