---
title: "What Is the `Vary` Header? A Simple Guide for Developers"
description: "Master the Vary header for proper HTTP caching. Learn how to prevent content mismatches and improve cache efficiency."
slug: "what-is-the-vary-header-a-simple-guide-for-developers"
url: "https://furkanbaytekin.dev/blogs/what-is-the-vary-header-a-simple-guide-for-developers"
author: "Furkan Baytekin"
category: "Software"
tags: []
published: 2025-12-14T08:40:08Z
updated: 2025-12-14T08:40:08Z
readTime: 3
cover: "https://myblogcms.furkanbaytekin.dev/uploads/cover/what-is-the-vary-header-a-simple-guide-for-developers+1765701474250"
---

When you build web apps that use caching-CDNs, reverse proxies, or even browser cache, the **`Vary` header** becomes one of, your best friends. It tells caches _how_ to treat different versions of the same URL, so users always get the correct response.

Let’s break it down.

## What Does the `Vary` Header Do?

A cache normally stores one version of a URL.
But sometimes, your server returns different responses depending on headers like:

- `Accept-Encoding` (gzip vs br)
- `User-Agent` (mobile vs desktop)
- `Accept-Language` (English vs Turkish)
- `Authorization` (logged-in vs guest)
- `Origin` (CORS decisions)

The `Vary` header says:

> “If this header changes, treat the response as a separate cache entry.”

Example:

```
Vary: Accept-Encoding
```

This tells the cache:
_“Store a gzip version and a br version separately, don’t mix them.”_

---

## Why the `Vary` Header Matters

### 1. Prevents Serving Wrong Content

Imagine your server returns Turkish content only when `Accept-Language: tr` is sent.

Without `Vary: Accept-Language`, the first cached TR version could be served to English users too. Disaster.

### 2. Helps with Device-Specific Views

If you send different HTML for mobile vs desktop:

```
Vary: User-Agent
```

Without it, desktop users might get mobile HTML.

### 3. Required for Some Security Features

Some servers vary behavior based on `Origin`.
Then you _must_ add:

```
Vary: Origin
```

Otherwise a cached response may incorrectly allow or deny CORS requests.

---

## Common `Vary` Header Use Cases

### Gzip / Brotli Compression

Most common one:

```
Vary: Accept-Encoding
```

Needed so caches don't serve Brotli to browsers that don't support it.

### Localization

```
Vary: Accept-Language
```

For language-specific pages.

### CORS

```
Vary: Origin
```

If you send dynamic CORS headers.

### Cookies / Auth

Be careful.
`Vary: Cookie` can kill cache efficiency because cookies are all unique.

But it's valid when you must split cached pages between logged-in and guest users.

---

## Examples

### Nginx

```nginx
add_header Vary Accept-Encoding;
```

### Express.js

```js
app.use((req, res, next) => {
  res.set("Vary", "Accept-Encoding");
  next();
});
```

### Go (net/http)

```go
w.Header().Add("Vary", "Accept-Encoding")
```

---

## Best Practices

- Keep `Vary` headers **short**. Don’t add unnecessary variations.
- Avoid `Vary: Cookie` unless absolutely required.
- Always set `Vary: Accept-Encoding` if you use gzip/brotli.
- If you use **dynamic CORS**, don’t forget `Vary: Origin`.

---

## Conclusion

The `Vary` header is tiny but powerful.
It keeps your caching layer smart, prevents content mismatches, and ensures users get the right version of your pages.

Use it correctly, and your app becomes faster and more reliable.
Forget it, and you’ll chase weird bugs for days.

---

Album of the blog:

<iframe data-testid="embed-iframe" style="border-radius:12px" src="https://open.spotify.com/embed/album/6NqP2oaumNCKtIoxIpgPKj?utm_source=generator" width="100%" height="152" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>
