Vary
Tells caches which request headers were used for content negotiation, so they know to store and serve separate variants keyed by those headers. Missing or wrong Vary causes users to see cached content meant for someone else (wrong language, encoding, or device).
Vary: <header-name>[, <header-name>...] | Vary: * Common directives / values
| Directive | Purpose |
|---|---|
| Accept-Encoding | Different variants for gzip/br/identity clients. |
| Accept-Language | Language-negotiated content. |
| Accept | Different MIME types negotiated (HTML vs JSON). |
| User-Agent | Device or browser adaptations — high cache-key cardinality, use sparingly. |
| Cookie | Personalized responses; typically defeats CDN caching entirely. |
| Origin | CORS responses that differ per origin. |
| * | Response varies on unspecified inputs — treat as uncacheable by shared caches. |
Examples
Vary: Accept-Encoding Standard for any gzipped/brotli response to keep encoded variants separate.
Vary: Accept-Encoding, Accept-Language Combine axes; cache key becomes URL + both header values.
Vary: Origin\nAccess-Control-Allow-Origin: https://app.example.com CORS best practice: prevents a cached response for site A being served to site B.
Vary: * Effectively marks the response as uncacheable by any shared cache.
Gotcha
Vary: User-Agent explodes the cache key across every browser build — usually a performance disaster; use only when truly serving distinct payloads. Forgetting Vary: Origin on CORS responses is the #1 source of 'works in Chrome, broken in Safari' CORS bugs.