Vary Header
A response header that tells caches which request headers should be included in the cache key. When the origin responds with Vary: Accept-Encoding, the cache stores separate copies for each Accept-Encoding value (gzip, br, identity). Without Vary, caches might serve gzip content to clients that c...
Full Explanation
The Vary header tells caches which request headers affect the response content. When a cache sees Vary: Accept-Encoding, it knows it needs to store separate copies of the response for each different Accept-Encoding value. A client requesting Accept-Encoding: gzip gets a different cached copy than one requesting Accept-Encoding: br. Without Vary, the cache might serve a gzip-compressed response to a client that only understands Brotli, or worse, serve compressed content to a client that cannot decompress at all.
You can list multiple headers: Vary: Accept-Encoding, Accept-Language means the cache key now includes both headers. This multiplies the number of cached variants. Two encodings times four languages equals eight cached copies of the same URL. This is fine for common combinations, but be careful with high-cardinality headers.
Some Vary values are effectively cache killers. Vary: Cookie means every unique cookie string creates a separate cache entry, which in practice means nothing gets served from cache. Vary: * tells caches that the response depends on something that cannot be captured in headers at all, so caching is completely disabled. User-Agent is another common mistake because there are thousands of unique User-Agent strings.
// Compression negotiation
HTTP/1.1 200 OK
Content-Encoding: gzip
Vary: Accept-Encoding
Cache-Control: max-age=86400
// Language negotiation
HTTP/1.1 200 OK
Content-Language: de
Vary: Accept-Language
Cache-Control: max-age=3600
// Multiple vary headers (cache stores variants per combination)
HTTP/1.1 200 OK
Content-Encoding: br
Content-Language: en
Vary: Accept-Encoding, Accept-Language
Cache-Control: max-age=3600
// Cache-killing: never do this on cacheable content
Vary: Cookie
Vary: *
Examples
Here is a practical example showing how Vary affects cache keys. The same URL produces different cache entries depending on the request headers listed in Vary.
# Same URL, different cache entries due to Vary: Accept-Encoding
curl -H "Accept-Encoding: gzip" https://cdn.example.com/api/data
# Cache key: GET|cdn.example.com|/api/data|gzip
curl -H "Accept-Encoding: br" https://cdn.example.com/api/data
# Cache key: GET|cdn.example.com|/api/data|br
curl -H "Accept-Encoding: identity" https://cdn.example.com/api/data
# Cache key: GET|cdn.example.com|/api/data|identity
Frequently Asked Questions
A response header that tells caches which request headers should be included in the cache key. When the origin responds with Vary: Accept-Encoding, the cache stores separate copies for each Accept-Encoding value (gzip, br, identity). Without Vary, caches might serve gzip content to clients that c...
Here is a practical example showing how Vary affects cache keys. The same URL produces different cache entries depending on the request headers listed in Vary.
# Same URL, different cache entries due to Vary: Accept-Encoding
curl -H "Accept-Encoding: gzip" https://cdn.example.com/api/data
# Cache key: GET|cdn.example.com|/api/data|gzip
curl -H "Accept-Encoding: br" https://cdn.example.com/api/data
# Cache key: GET|cdn.example.com|/api/data|br
curl -H "Accept-Encoding: identity" https://cdn.example.com/api/data
# Cache key: GET|cdn.example.com|/api/data|identity