VaryVary tells caches which request-header values this response depends on. Even for the same URL, a cache treats differing values of the listed headers as separate cache entries, preventing the wrong representation from being served to the wrong user.
It is the key mechanism for cache correctness in responses that use content negotiation (compression, language, media type) or CORS.
For example, if the server emits a gzip version and an uncompressed version based on Accept-Encoding, then without Vary: Accept-Encoding a cache could hand a gzip response to a client that doesn't support gzip, showing broken content. A multilingual site choosing language from Accept-Language needs Vary: Accept-Language.
In CORS, if the server reflects Origin to produce Access-Control-Allow-Origin dynamically, it must also emit Vary: Origin. Otherwise a shared cache reuses origin A's response for origin B, breaking CORS or causing cache poisoning.
Vary: * means the response depends on unspecified request factors beyond the URL and is effectively uncacheable. Also, the higher the cardinality of the listed header combination (e.g. User-Agent), the worse the cache fragmentation and the lower the hit rate — list only the headers you truly need.
Vary: <header>[, <header>]* | *e.g. Vary: Accept-Encoding, Accept-Language
Accept-Encoding | Response differs by compression negotiation (gzip/br) — essential for caching compressed responses. |
Accept-Language | Response differs by language negotiation (multilingual sites). |
Accept | Representation differs by requested media type (content negotiation). |
Origin | Splits CORS caches by request origin — prevents cross-origin cache poisoning. |
Cookie | Response differs by cookie (per-user) — effectively defeats shared caching. |
* | Varies on unspecified request factors — effectively uncacheable across requests. |