Vary

A single URL often produces different responses based on Compression, language, or device type. The Vary response header tells caches which request headers influenced the response, so the correct representation gets stored and served.

Usage

A single URL often produces different responses depending on what the client sends. A server compressing with gzip for one client and Brotli for another serves two distinct representations of the same resource. The Vary header records which request headers caused the server to choose a particular representation, giving caches the information needed to store and match the right copy.

When a cache receives a request for a URL with a stored response, the cache compares the listed Vary headers between the new request and the stored one. If the values match, the cached response is valid. If they differ, the cache fetches a fresh response from the origin.

The most common values are Accept-Encoding (for Compression negotiation) and Accept (for content negotiation). Dynamic serving setups serving different HTML to mobile and desktop clients based on the User-Agent string add Vary: User-Agent to signal this variation.

The wildcard value * means every request is considered unique and effectively disables caching for the resource. This is rarely appropriate and most caches treat a Vary: * response as uncacheable.

Note

Google does not use the Vary header to understand mobile and desktop relationships for search indexing. The header is a caching mechanism, not a search signal. Sites using dynamic serving with Vary: User-Agent still benefit from correct cache behavior, but the header itself has no effect on how Google discovers or indexes mobile content. Google also advises against making m-dot URLs the canonical version despite mobile-first indexing, recommending responsive design as the preferred configuration.

Directives

Accept-Encoding

Indicates the response varies by the Accept-Encoding request header. Different Compression algorithms (gzip, br, zstd) produce different response bodies for the same resource. This is the most widely used Vary value.

Accept

Indicates the response varies by the Accept request header. Content negotiation delivers different media types (HTML, JSON, XML) from the same URL based on client preference.

Accept-Language

Indicates the response varies by the Accept-Language request header. Multilingual sites serving localized content from the same URL include this value.

User-Agent

Indicates the response varies by the User-Agent request header. Dynamic serving configurations deliver different HTML to mobile and desktop clients from the same URL.

Vary: Cookie means the response differs based on the Cookie header value. Caches store a separate variant for each unique Cookie string, causing significant cache fragmentation since every authenticated user has a different session cookie. Restrict Vary: Cookie to responses that genuinely depend on cookie values (personalized pages, dashboards) and avoid setting the value on public static assets.

* (wildcard)

The wildcard value signals the response varies by factors not captured in a request header. Caches treat this as uncacheable. Rarely used intentionally.

Example

A server compresses responses using the encoding requested by the client. The Vary: Accept-Encoding header tells intermediate caches to store separate copies for gzip and Brotli requests rather than serving a gzip-compressed response to a Brotli-capable client.

Vary: Accept-Encoding

A content negotiation setup delivers JSON or HTML from the same endpoint. The cache stores separate responses based on the Accept header value.

Vary: Accept

Multiple headers influencing the response are listed as a comma-separated value. Here the response depends on both the accepted encoding and the preferred language.

Vary: Accept-Encoding, Accept-Language

A dynamic serving configuration delivers different HTML to mobile and desktop user agents. The cache stores separate versions keyed by the full User-Agent string.

Vary: User-Agent

Pairing Vary with Cache-Control controls both what varies and how long each variant stays fresh.

Cache-Control: public, max-age=3600
Vary: Accept-Encoding

Troubleshooting

Caching problems caused by a missing or overly broad Vary header often surface as users receiving wrong content.

  1. CDN serving the wrong cached variant. A server returns different content based on a request header but omits the matching Vary value. The CDN caches the first response and serves the same copy to all clients regardless of their request headers. Add the relevant header name to the Vary list. Test by sending requests with different header values through curl and comparing the X-Cache or Age response headers: curl -H "Accept-Encoding: gzip" -v https://cdn.example.re/style.css curl -H "Accept-Encoding: br" -v https://cdn.example.re/style.css

  2. Cache fragmentation from Vary: User-Agent. The User-Agent string has thousands of unique values. Listing User-Agent in the Vary header creates a separate cache entry for nearly every visitor, destroying cache hit rates. CDNs like Cloudflare and Fastly normalize the User-Agent into device classes. Where possible, use a normalized header such as Sec-CH-UA-Mobile or a CDN-specific device-type header instead of the raw User-Agent.

  3. Vary: * disabling caching entirely. The wildcard tells caches that the response varies by factors outside any request header. Most caches treat this as uncacheable and never serve a stored copy. Remove Vary: * unless the intention is to disable all caching for the resource. If a specific request header drives the variation, name the header explicitly.

  4. Missing Vary: Origin causing CORS cache poisoning. A server returns a dynamic Access-Control-Allow-Origin value based on the Origin request header but does not include Vary: Origin. A CDN caches the response with one origin and serves the same CORS header to a different origin, causing browsers to block the response. Add Vary: Origin to every response that reflects a dynamic origin value. To diagnose, send two curl requests from different origins and check whether the cached Access-Control-Allow-Origin changes: curl -H "Origin: https://a.example.re" -v https://api.example.re/data curl -H "Origin: https://b.example.re" -v https://api.example.re/data

  5. Vary: Accept-Encoding inconsistencies between gzip and Brotli. Some origin servers compress with gzip but a CDN edge re-compresses to Brotli, causing a mismatch between the cached encoding and the Vary key. Ensure the origin and the CDN agree on encoding behavior. In nginx, set gzip_vary on; to add Vary: Accept-Encoding automatically. When using Brotli alongside gzip, confirm both modules add the same Vary value so the cache stores separate entries per encoding.

See also

Last updated: April 4, 2026