Articles

Gzip vs Brotli: HTTP Compression Compared

Gzip and Brotli both shrink HTTP responses before they hit the wire. How each algorithm works, and why Brotli usually compresses text tighter.

Takina Takina · · 5 min read
Code displayed on a dark-themed editor

Gzip and Brotli are the two compression algorithms browsers and servers use to shrink HTTP responses before they travel over the network, and Brotli generally produces smaller files for text-based content like HTML, CSS, and JavaScript because it ships with a built-in dictionary of common web strings. Both are supported by every modern browser and configurable in most web servers and CDNs, so the choice mostly comes down to how much CPU time you’re willing to spend at request time.

How compression fits into a request

When a browser requests a resource, it sends an Accept-Encoding header listing the compression formats it understands, typically gzip, deflate, br. The server picks one, compresses the response body, and labels it with a Content-Encoding header. The browser decompresses it transparently before rendering. This exchange happens on nearly every text response on the modern web — see how HTTP caching headers work for the related mechanism that avoids re-sending a response at all.

Compression reduces bytes over the wire, which matters most on the critical rendering path: a smaller HTML or CSS payload parses and paints sooner, which is part of why it factors into Core Web Vitals scores.

How gzip works

Gzip is built on DEFLATE, a combination of LZ77 (replacing repeated byte sequences with back-references) and Huffman coding (assigning shorter bit patterns to more frequent bytes). It’s been the default HTTP compression format since the late 1990s, which means it’s supported everywhere, cheap to compute, and well understood by every caching layer and proxy in existence.

Gzip’s main limitation is that its dictionary is built from the file being compressed — it has no prior knowledge of what a typical HTML or CSS file looks like. Every occurrence of <div class= has to be learned fresh within each response.

How Brotli works

Brotli, developed at Google, also uses LZ77-style back-references and Huffman coding, but adds two things gzip lacks:

  • A static dictionary of roughly 13,000 common strings drawn from web content — HTML tags, CSS properties, JavaScript keywords, common English words. This gives Brotli a head start on typical web assets that gzip doesn’t get.
  • Context modeling, which predicts the next byte based on more surrounding context than gzip’s Huffman coding considers, squeezing out more redundancy.

At its highest compression levels Brotli is noticeably slower to compress than gzip, but decompression speed is comparable. That asymmetry is exactly why Brotli fits the web well: you compress once (often at build time or on first request, then cache the result) and decompress millions of times on the client.

Gzip vs Brotli at a glance

GzipBrotli
Algorithm baseDEFLATE (LZ77 + Huffman)LZ77 + context modeling + static dictionary
Typical text compression ratioGoodBetter, especially on HTML/CSS/JS
Compression speed (high levels)FasterSlower
Decompression speedFastFast, comparable to gzip
Browser supportUniversalUniversal in modern browsers
Best forDynamic responses compressed on the flyStatic assets pre-compressed at build time

Static vs dynamic compression

The practical difference between the two algorithms matters most when you decide when to compress:

  • Dynamic responses — API replies, server-rendered HTML that changes per request — need to be compressed on every request. Here gzip’s speed advantage can matter if CPU is constrained, though many servers now default to a fast Brotli level for this case too.
  • Static assets — bundled JavaScript, CSS files, fonts — only need to be compressed once, at build or deploy time, and served from a CDN or cache afterward. Since compression time is paid once and decompression happens millions of times, it makes sense to spend extra CPU here and use Brotli at its maximum quality setting.

This is why most build tooling that emits precompressed assets (.br and .gz files alongside the originals) favors high-quality Brotli for the static bundle and lets the server fall back to gzip for clients or intermediaries that don’t advertise br support.

Brotli’s quality levels

Brotli exposes a quality parameter from 0 (fastest, weakest compression) to 11 (slowest, strongest compression), and the setting matters more than with gzip because the gap between Brotli’s fast and slow ends is wider. At low quality levels, Brotli’s compression ratio is close to gzip’s, and its speed advantage disappears — you’re not getting much benefit from switching algorithms. The real gains show up at quality 9 through 11, where Brotli’s static dictionary and context modeling get to do their work, but compression time at level 11 can be an order of magnitude slower than gzip at its default level. This is precisely why the static-asset-vs-dynamic-response distinction matters so much in practice: quality 11 is a reasonable choice for a JavaScript bundle compressed once at build time, and a poor choice for compressing an API response on every request.

Most server software with Brotli support defaults to a moderate quality level for dynamic content — enough to beat gzip without adding noticeable latency — while build tools that precompress static assets typically go straight to the maximum setting, since the extra build time is a one-time cost paid long before any user sees the result.

Content negotiation and fallbacks

Because Brotli support is signaled by the client’s Accept-Encoding header, servers need to fall back gracefully for any request that doesn’t list br. This mostly matters for older clients and some intermediary proxies and caches that don’t advertise or forward Brotli support. A correctly configured server checks the Accept-Encoding header per request and serves whichever precompressed variant (or on-the-fly compression) matches what that specific client claims to support, falling back to an uncompressed response only if neither gzip nor Brotli is advertised at all — which is rare on the modern web but still worth handling rather than assuming.

One detail worth getting right: caching layers sitting in front of the origin server need to vary their cache key on Accept-Encoding, or a Brotli-compressed response cached for one client could get served to a client that only advertised gzip support and doesn’t know how to decode it.

What compression does not replace

Compression shrinks a payload; it doesn’t eliminate the request. Reducing the number and size of requests still matters — lazy-loading images and choosing efficient image formats like WebP or AVIF address a different bottleneck than text compression does, since compressed image formats are already entropy-coded and gain little from a second pass of gzip or Brotli. Applying HTTP compression to already-compressed binary formats (images, video, zip archives) wastes CPU for negligible savings — most server configs correctly restrict gzip/brotli directives to text MIME types like text/html, text/css, application/javascript, and application/json.

The takeaway

Gzip is the universal fallback: fast, simple, and supported by anything that speaks HTTP. Brotli compresses text-based web assets tighter, mostly thanks to its built-in dictionary of common web strings, at the cost of slower compression (not decompression). The common production setup serves Brotli-compressed static assets built once at deploy time, with gzip as the fallback for clients or proxies that don’t advertise br support in their Accept-Encoding header.

Takina Takina · · 4 min read

HTTP Range Requests and Partial Content, Explained

HTTP range requests let a client ask for just part of a resource, enabling video seeking, resumable downloads, and partial file fetches over HTTP.

#Networking #Web Development #Performance
Takina Takina · · 4 min read

HTTP/2 vs HTTP/3: What Actually Changed

HTTP/2 fixed request multiplexing but stayed on TCP; HTTP/3 moves to QUIC over UDP to kill head-of-line blocking at the transport layer. The real differences.

#Networking #Performance #Web Development
Takina Takina · · 5 min read

HTTP Caching Headers: Cache-Control and ETag Explained

Cache-Control and ETag are the two headers that control HTTP caching — how long a response stays fresh and how to revalidate it cheaply, explained.

#Web Development #Performance #Networking