Content-Encoding gzip vs br in nginx: what stock nginx sends (tested)
Content-Encoding says how the body was compressed; the client lists what it accepts in Accept-Encoding. We checked what the official nginx Docker image does with each.
1. What stock nginx sent (gzip on)
| Accept-Encoding | Content-Encoding | Bytes |
|---|---|---|
| (identity) | none | 187,779 |
gzip | gzip | 23,515 |
br only | none | 187,779 |
gzip, deflate, br, zstd (what Chrome sends) | gzip | 23,515 |
The official image has no Brotli: brotli on; fails with unknown directive "brotli". A browser offering br simply gets gzip, which is fine. Every response carried Vary: Accept-Encoding because of gzip_vary on, so caches keep compressed and plain copies apart (what Vary does, measured).
2. The gzip config we ran
gzip on;
gzip_types application/javascript; # text/html is always included; add text/css application/json image/svg+xml ...
gzip_vary on;
gzip_comp_level 9 gave 23,688 bytes vs 23,515 at the default level 1 on this file: higher levels cost CPU and are not guaranteed to be smaller. Levels 4–6 are the usual compromise; measure on your own files.
3. Getting br
Brotli usually beats gzip on text and every current browser supports it, but nginx needs the separate ngx_brotli module (a distro package or an image built with it), then brotli on; brotli_types …;. Many CDNs (Cloudflare and others) apply Brotli at the edge without touching nginx. Pre-compress static files (.br/.gz next to the original) to pay the CPU cost once.
4. Checking a site
curl -s -o /dev/null -D- -H 'Accept-Encoding: gzip, br' https://your-site/app.js | grep -i -E 'content-encoding|vary'
No Content-Encoding line means the response was not compressed: check gzip_types for its Content-Type first.
Frequently asked questions
What does Content-Encoding: gzip mean?
The body was compressed with gzip and the browser unpacks it. In our test nginx shrank a 187,779-byte script to 23,515 bytes.
Does nginx support Brotli (br)?
Not the official Docker image: 'brotli on' failed with unknown directive, and a br-only request got the uncompressed file. You need the ngx_brotli module.
gzip or br?
br is usually smaller for text; gzip is universally supported. Offer both and the server picks; stock nginx picked gzip for Chrome's 'gzip, deflate, br, zstd'.
Is a higher gzip_comp_level better?
Not necessarily: level 9 produced a slightly larger file than the default level 1 in our test, at more CPU cost.
Written with AI assistance. Measured on 2026-10-01 with curl 8.14.1 against the official nginx:alpine image (nginx 1.31.6, throwaway container) serving a generated 187,779-byte JavaScript file. The file is repetitive, so its compression ratios are higher than typical code; compare settings, not absolute ratios. Brotli sizes were not measured (no brotli module or tool was available); the brotli module lines, the CDN remark and Chrome's usual Accept-Encoding value are from documentation, not this test. PlainHeaders is our extension; curl is free.