Card 06/ 11

ConceptDifficulty: Intermediate2 min

Vary: One URL, Several Representations

A cache must know which request headers change the response, or it serves the English page to a French reader.

The Vary response header lists the request headers that change the response, so a cache stores one copy per combination of their values instead of one copy per URL. Without it, a cache that stored the English response for /products would hand it to a client that asked for French, because to the cache both requests look the same.

Two requests to one URL, the cache key under Vary Accept-Language, and the copy served
RequestAccept-LanguageCache keyCopy served
GET /products, firsten/products + enFetched from the origin and stored
GET /products, secondfr/products + frNot the English copy; fetched and stored
GET /products, thirden/products + enThe English copy from the cache

The cache key is what a cache uses to find a stored response. By default it is the method and the URL. Vary: Accept-Language adds the value of that request header, so each language gets its own entry.

Common cases.

  • Vary: Accept-Encoding, so a client that cannot read compressed responses is not given one. Servers that compress usually add it automatically.
  • Vary: Accept, when one URL returns JSON or CSV depending on the request.
  • Vary: Authorization or Vary: Cookie, when the response differs by user. It keeps users' copies apart in a shared cache, but turns that cache into one entry per user, which it can rarely reuse; private is usually the better answer for personal data.

Keep the list short. Every header in Vary splits the cache further. Vary: User-Agent creates an entry for each of thousands of browser versions and makes the cache nearly useless. Some CDNs ignore Vary values they do not support and refuse to cache, so check what yours does.

Vary is not a security control. If a response is personal, mark it private or no-store. Relying on Vary: Cookie to keep users apart fails the moment a cache in the path ignores it.

So add each request header the response depends on to Vary, and no others.