Learn

Web Compression Explained: Gzip vs. Brotli vs. Deflate

Most text-based HTTP responses — HTML, CSS, JavaScript, JSON, SVG — compress down to a fraction of their original size before they ever leave the server. The browser decompresses them automatically, invisibly, in milliseconds. Whether that happened at all, and which algorithm did it, is reported in a single response header: content-encoding. This site's own Website Health Check reads that header and reports it as the Compression row; this page covers what it means, why it matters, and how to turn it on if it's missing.

What HTTP Compression Actually Is

A web server can compress a response body before sending it, the same way a .zip file compresses a folder — the bytes on the wire are smaller, and the browser reverses the process before rendering. Two headers coordinate this on every request:

  • accept-encoding (request) — sent by the browser, listing which algorithms it can decompress. Every modern browser sends something like gzip, deflate, br, zstd.
  • content-encoding (response) — sent by the server, naming whichever algorithm it actually used, for example br. Absent entirely means the response went out uncompressed.

Compression is negotiated per request, not fixed per site — a server can legally send the same page compressed to one client and uncompressed to another, based on what that client's own accept-encoding header claims to support.

Gzip, Brotli, and Deflate Compared

  • gzip — the long-standing default, supported by effectively every HTTP client in existence since the late 1990s. Not the smallest output of the three, but the safest choice when compatibility with very old clients matters.
  • brotli (br) — developed at Google specifically for web content, typically 15-20% smaller than gzip on the same text at a comparable compression level. Supported by every browser released since roughly 2017; the modern default for anything served over HTTPS, since brotli is only advertised by browsers on secure connections.
  • deflate — the raw compression algorithm gzip itself is built on, without gzip's own header/checksum framing. Rarely sent deliberately today; its inconsistent framing across implementations made it a source of real interop bugs, and gzip solved the same problem more reliably.

A well-configured server offers brotli first and falls back to gzip for the small share of clients that don't advertise br support — exactly what the accept-encoding negotiation above exists to handle automatically, per request.

Why It Matters

Text compresses extremely well — a typical HTML or JavaScript file shrinks by 60-80%, sometimes more for highly repetitive content like a large JSON payload. Every one of those saved bytes is bytes the connection doesn't have to transfer before the browser can start parsing and rendering, which matters most on exactly the connections where it matters most: mobile networks, long geographic distances, or anything short of a fast fixed line. The tradeoff is a small amount of CPU time on the server to compress the response — negligible for brotli/gzip at normal levels, and almost always worth it.

What Not to Compress

Compression only helps on content that isn't already compressed. Re-compressing an already-compressed format wastes CPU for zero size benefit, and occasionally makes the file marginally larger:

  • Images — JPEG, PNG, WebP, and AVIF are already compressed formats; gzip or brotli on top of them does essentially nothing.
  • Video and audio — MP4, WebM, and most audio codecs are compressed at encode time, well before HTTP is involved.
  • Archives and fonts — a .zip, or a .woff2 font file, are compressed containers already; woff2 specifically has brotli-based compression built into the format itself.

This is why a well-configured server applies compression selectively by content type — text/html, text/css, application/javascript, application/json, image/svg+xml — rather than blanket-compressing every response regardless of what it actually contains.

Enabling Compression

Most servers and CDNs support this natively; it's usually a configuration flag rather than anything requiring application code changes.

nginx

gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
gzip_min_length 256;

brotli on;
brotli_types text/css application/javascript application/json image/svg+xml;

Brotli support requires the separate ngx_brotli module — not compiled into nginx's default build.

Apache

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

mod_deflate handles gzip despite the module's name; brotli needs the separate mod_brotli, available since Apache 2.4.26.

CDNs and Managed Platforms

Cloudflare, Vercel, Netlify, AWS CloudFront, and most managed hosts compress eligible responses automatically at the edge, with no configuration needed — worth confirming with a direct check rather than assuming, since defaults and eligible content types vary by provider.

Checking Whether It's Actually On

Run the Website Health Check, or inspect the content-encoding header directly with the HTTP header checker — a curl request shows the same thing from the command line:

curl -sI -H "Accept-Encoding: br, gzip" https://example.com | grep -i content-encoding

No content-encoding line in the response means the server isn't compressing that particular response, regardless of what it's capable of in general — the check has to be per response, since a misconfigured content-type rule can leave some pages compressed and others not.

Frequently Asked Questions

Is missing compression actually a problem, or just a nice-to-have?

Worth fixing, rarely urgent. Uncompressed responses still work correctly — nothing breaks — they just transfer more bytes than necessary, which shows up as slower page loads, most noticeably on slower or higher-latency connections. It's one of the cheapest performance fixes available: a config flag, not a code change.

Should I pick gzip or brotli?

Serve both, and let accept-encoding negotiation pick automatically — that's what it's for. Brotli first for the size advantage, gzip as the fallback for the small share of clients that don't advertise brotli support. Neither needs to be chosen manually per request.

Why is my image folder not getting smaller with compression on?

Images are already compressed at the format level (JPEG, PNG, WebP, AVIF) — running gzip or brotli over already-compressed bytes finds essentially nothing left to compress. Image size reductions come from format choice and encode quality settings, not HTTP-level compression.

Does HTTPS affect compression?

Indirectly: brotli is only advertised by browsers over HTTPS connections, not plain HTTP, so a site still on HTTP loses access to it and falls back to gzip. This is unrelated to content-encoding being sent for a data-security reason (BREACH, a compression-related information leak affecting response bodies that reflect a secret alongside attacker-controlled input) — a real but narrow risk, specific to pages that mix a secret token with user input in the same compressed response, not a reason to avoid compression generally.

Check any domain's current compression status with the Website Health Check.