HttpFixerBlogHeaders → The Vary Header — Why Your CDN Serves the Wrong Cached Response
Headers

The Vary Header — Why Your CDN Serves the Wrong Cached Response

Updated April 2026

Reading this? Verify your fix in real-time. Audit your cache headers → EdgeFix

You set up Brotli compression. Your CDN caches the first request. The second user, whose browser does not support Brotli, gets served the Brotli-compressed version and cannot decompress it. This is a Vary header problem.

When you need Vary and what to set

SituationAdd this Vary valueWhy
Multiple compression formats (gzip, Brotli, zstd)Accept-EncodingDifferent encodings = different response bodies
CORS with explicit originsOriginACAO header value differs per origin
Content negotiation (JSON vs HTML)AcceptSame URL, different content type
InternationalisationAccept-LanguageDifferent language = different response
Mobile vs desktop contentUser-AgentWarning: very broad, hurts cache efficiency

The most common one — compression

# Nginx — you probably have this already (gzip adds it automatically)
# But verify it is there:
gzip_vary on;  # adds Vary: Accept-Encoding for gzip responses

# For Brotli:
brotli_types text/html text/css application/javascript;
# Also add:
add_header Vary "Accept-Encoding" always;

CORS + Vary: Origin

When you return a specific origin in Access-Control-Allow-Origin instead of *, you must add Vary: Origin. Otherwise the CDN caches the response for one origin and serves it to requests from a different origin — which will have the wrong ACAO value.

# Nginx — CORS config with Vary
add_header Access-Control-Allow-Origin "https://yourapp.com" always;
add_header Vary "Origin" always;  # required when using explicit origins

# Express
app.use((req, res, next) => { res.vary("Origin");  // add Vary: Origin before setting ACAO next();
});

Multiple Vary values

# Correct — comma-separated list
Vary: Accept-Encoding, Origin

# In Nginx — multiple add_header lines for Vary stack incorrectly
# Use a single directive:
add_header Vary "Accept-Encoding, Origin" always;

# Vercel (vercel.json)
{ "key": "Vary", "value": "Accept-Encoding, Origin" }

Check current Vary header

curl -I https://yoursite.com/ | grep -i vary
# Should show: vary: Accept-Encoding
# If you use CORS with specific origins, also: vary: Origin

What not to vary on

# Never use:
Vary: * # disables caching entirely
Vary: Cookie # prevents any CDN caching (every request unique)
Vary: Authorization  # same as Cookie — kills CDN efficiency

# For authenticated content:
# Do not use Vary: Authorization
# Use Cache-Control: private, no-store instead

Use EdgeFix to audit your live site's Vary, Cache-Control, Age, and X-Cache headers together — it shows exactly what the CDN is caching and what it should not be.

Audit your cache headers → EdgeFix
Check if your domain is on the HSTS preload list → HSTS Preload Checker