# Content-Encoding

> Learn how Content-Encoding specifies compression algorithms (gzip, br, deflate) used to encode response bodies. Reduce bandwidth and improve load times.

Source: https://howhttpworks.com/headers/content-encoding
Last reviewed: 2026-10-04

> **TL;DR:** Names the compression applied to the response body (`gzip`, `br`, `zstd`, rarely `deflate`). The client undoes it before using the body. Servers should only pick an encoding the client listed in `Accept-Encoding`, and add `Vary: Accept-Encoding` so caches keep the variants apart.

## What is Content-Encoding?

**Content-Encoding** tells the browser how the response body has been compressed or encoded. It's like a label on a compressed file that says "this was zipped with gzip" so the browser knows how to decompress it.

Text formats such as HTML, CSS, JavaScript and JSON usually shrink a lot; how much depends on the content, so measure your own responses (see below). The [HTTP compression guide](https://howhttpworks.com/guides/http-compression) covers choosing between gzip, Brotli and zstd in depth.

## How It Works

**1. Browser requests with compression support:**

```http
GET /style.css HTTP/1.1
Host: example.com
Accept-Encoding: gzip, deflate, br
```

**2. Server compresses response and adds header:**

```http
HTTP/1.1 200 OK
Content-Type: text/css
Content-Encoding: gzip
Content-Length: 1234

[compressed CSS data]
```

**3. Browser automatically decompresses** the response before using it.

## Common Encoding Types

### gzip

Most widely supported compression:

```http
Content-Encoding: gzip
```

- Supported by all modern browsers
- Good compression on text at low CPU cost
- Fast compression/decompression

### br (Brotli)

Modern compression algorithm:

```http
Content-Encoding: br
```

- Usually smaller output than gzip on text
- Supported by all current browsers
- High levels are slow to compress, so large static files are often compressed once at build time

### zstd (Zstandard)

```http
Content-Encoding: zstd
```

- Defined for HTTP in RFC 8878
- Supported in Chrome and Edge 123+ and Firefox 126+; Safari support is partial (see the [compression guide](https://howhttpworks.com/guides/http-compression) for details as of October 2026)
- Fast to compress, which suits dynamic responses

### deflate

Older compression method:

```http
Content-Encoding: deflate
```

- Less efficient than gzip
- Rarely used today

### identity

No compression (default):

```http
Content-Encoding: identity
```

- Usually omitted when no compression is used

## Multiple Encodings

You can apply multiple encodings in order:

```http
Content-Encoding: gzip, deflate
```

Browser decompresses in reverse order: deflate first, then gzip.

## Measure the savings on your own responses

Compression ratios depend on the content, so check your real responses instead of trusting a rule of thumb:

```bash
for enc in identity gzip br zstd; do
  printf '%-8s ' "$enc"
  curl -s -H "Accept-Encoding: $enc" -o /dev/null -w '%{size_download} bytes\n' https://example.com/app.js
done
```

If every line shows the same size, the server ignored the encoding you asked for.

## What Gets Compressed

**✅ Compress these:**

- HTML, CSS, JavaScript
- JSON, XML, SVG
- Text files, and TTF/OTF fonts (WOFF2 is already Brotli-compressed)
- Any text-based content

**❌ Don't compress these:**

- Images (JPEG, PNG, WebP) - already compressed
- Videos (MP4, WebM) - already compressed
- Audio files (MP3, AAC) - already compressed
- Already compressed files (ZIP, GZIP)

## Server Configuration

### Apache

```apache
# Enable gzip compression
LoadModule deflate_module modules/mod_deflate.so

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css text/javascript
    AddOutputFilterByType DEFLATE application/javascript application/json
</IfModule>
```

### Nginx

```nginx
# Enable gzip compression
gzip on;
gzip_types text/css text/javascript application/javascript application/json;
gzip_min_length 1000;
```

### Node.js (Express)

```javascript
const compression = require('compression')
app.use(compression())
```

## Browser Support

- **gzip:** every browser and HTTP client
- **br:** all current browsers
- **zstd:** Chrome and Edge 123+, Firefox 126+; Safari partial
- **deflate:** accepted widely but rarely used, partly because early implementations disagreed on whether it meant raw DEFLATE or zlib-wrapped data

Because a server should only send an encoding the client listed in `Accept-Encoding`, enabling a newer one does not break older clients as long as gzip stays on.

## Security Considerations

**BREACH Attack:** Compression can leak information when:

- Response contains user secrets (CSRF tokens)
- Response reflects user input
- Response is compressed

**Mitigation:**

- Don't compress responses with secrets
- Use random padding
- Separate secret data from user input

## Getting Content-Encoding right

**1. Always compress text-based content:**

```http
Content-Encoding: gzip
```

**2. Use Brotli for modern browsers:**

```http
Content-Encoding: br
```

**3. Set minimum file size threshold:**

```text
Only compress files > 1KB
```

**4. Don't compress already-compressed files:**

```http
Skip: .jpg, .png, .mp4, .zip
```

**5. Check what you actually send:**

```bash
curl -sI -H 'Accept-Encoding: br, gzip' https://example.com/ | grep -i -E 'content-encoding|vary'
```

## Common Issues

**Problem:** Content appears garbled
**Solution:** Server sent compressed data but forgot `Content-Encoding` header

**Problem:** Slow compression
**Solution:** Use faster compression levels or cache compressed versions

**Problem:** Double compression
**Solution:** Don't compress already-compressed files

## Related Headers

- [Accept-Encoding](https://howhttpworks.com/headers/accept-encoding) - Client's supported compression methods
- [Content-Length](https://howhttpworks.com/headers/content-length) - Size of compressed content
- [Content-Type](https://howhttpworks.com/headers/content-type) - Type of content being compressed
- [Vary](https://howhttpworks.com/headers/vary) - Cache different compressed versions
