How does HTTP compression (gzip/brotli) work, and when does it actually help vs. hurt?
Compression trades CPU for bandwidth via content negotiation — get the trade wrong and you'll burn cycles re-compressing a JPEG, or worse, open a side channel that leaks secrets over TLS.
LEARN BY DOINGPut your intuition to work3 steps
How does HTTP compression (gzip/brotli) work, and when does it actually help vs. hurt?
Use the lesson’s examples and explanation to check your idea.
Personal reflection. Nothing is sent to an AI service.#Why interviewers ask this
"Turn on gzip" is a one-line config change that most engineers have made without ever being asked to justify it. The senior version of this question checks whether you understand compression as a negotiated, CPU-for-bandwidth trade rather than a switch that's always safe to flip — because the same setting that shaves 70% off a JSON payload can also burn CPU for nothing on an image endpoint, or, in the worst case, open a genuine information-leak side channel over TLS.
#Content negotiation: the client offers, the server decides
Compression on the web is negotiated per-request, not configured once and forgotten. The client lists what it can decode in the Accept-Encoding request header (gzip, deflate, br, typically in the client's preference order); the server picks one — or none — and marks its choice with the Content-Encoding response header. If the server's response varies depending on that request header (which it does, the moment compression is conditional), it must also send Vary: Accept-Encoding, or a shared cache sitting in front of it (a CDN, a reverse proxy) can serve a brotli-encoded response to a client that only understands gzip, or worse, an uncompressed body to a client expecting compression header semantics it never got.
#How gzip and brotli actually compress
Gzip (and the closely related raw deflate) is built on LZ77 — it slides a window over the data looking for repeated byte sequences and replaces repeats with short back-references, then Huffman-codes the result to squeeze the remaining symbol frequencies further. This is exactly why compression ratio depends so heavily on redundancy: JSON, HTML, CSS, and JS are full of repeated punctuation, keys, and whitespace, so they compress extremely well, often 60-80% smaller. Brotli, developed by Google, builds on the same LZ77-plus-entropy-coding foundation but adds a large static dictionary pre-trained on common web content (HTML tags, JS keywords, common phrases) and more sophisticated context modeling, which is why brotli at a comparable setting typically beats gzip's ratio by another 15-25% on text — at the cost of being slower to compress at its highest quality levels, though decompression speed is comparable to gzip's.
Both algorithms expose a quality/level knob that trades CPU time for ratio: gzip runs 1 (fastest, worst ratio) through 9 (slowest, best ratio), brotli runs 0 through 11. For content compressed once and served many times — static assets — using the highest level costs nothing at request time and is free money. For content compressed fresh on every request — dynamic API responses — a mid-level setting (gzip 6, brotli 4-5) is usually the right trade, since squeezing out the last few percent of size isn't worth doubling your CPU cost per request.
#When compression actually helps
Compression earns its CPU cost when the payload is text-like and has real redundancy to exploit: JSON API responses, HTML documents, CSS, JavaScript, SVG, and plain text all fall in this bucket, typically shrinking by half or more. It also matters most exactly where bandwidth is the bottleneck relative to CPU — mobile clients on constrained networks, geographically distant clients paying full round-trip latency per byte, or high-traffic endpoints where the aggregate bandwidth bill dwarfs the aggregate CPU bill.
#When compression hurts
Two failure modes show up constantly in real systems. First, recompressing already-compressed binary formats — JPEG, PNG, MP4, most modern video/audio codecs, ZIP, PDF — wastes CPU for little or no gain, because those formats already removed the redundancy compression relies on; in the worst case, compression adds a few bytes of framing overhead and the "compressed" output is larger than the input. Second, compressing very small responses costs more in CPU and per-encoding overhead (gzip's own header/footer, brotli's dictionary setup) than it saves in transferred bytes, which is why real deployments set a minimum-size threshold (often around 1 KB) below which compression is simply skipped.
#Configuring it for real
# RequestGET /api/products HTTP/1.1Host: api.shop.exampleAccept-Encoding: gzip, deflate, br# ResponseHTTP/1.1 200 OKContent-Type: application/jsonContent-Encoding: brVary: Accept-EncodingContent-Length: 4213
// Express — compression middleware, tuned to skip small and already-compressed payloadsimport express from "express";import compression from "compression";const app = express();app.use(compression({threshold: 1024, // bodies under 1 KB aren't worth compressingfilter: (req, res) => {const contentType = String(res.getHeader("Content-Type") || "");if (/image|video|zip|pdf/i.test(contentType)) return false; // already compressedreturn compression.filter(req, res);},}));app.get("/api/products", (req, res) => {res.json(bigProductCatalog); // middleware handles negotiation and encoding});
gzip on;gzip_types application/json text/css application/javascript text/html image/svg+xml;gzip_min_length 1024;gzip_comp_level 6;gzip_vary on;# brotli usually needs the ngx_brotli module compiled inbrotli on;brotli_types application/json text/css application/javascript text/html image/svg+xml;brotli_comp_level 5;
#gzip vs. brotli, side by side
| gzip | brotli | |
|---|---|---|
| Base algorithm | LZ77 + Huffman | LZ77 + Huffman + static web dictionary + context modeling |
| Typical ratio vs. gzip | baseline | ~15-25% smaller on text |
| Compression speed at max quality | Fast even at level 9 | Noticeably slower at quality 10-11 |
| Decompression speed | Fast | Comparable to gzip |
| Browser support | Universal | Universal in modern browsers (over HTTPS) |
| Best use | Dynamic responses compressed on the fly | Static assets pre-compressed at build time |
🧠 Check your understanding
0/2 · 0/2 answered1. An API endpoint serves a 400-byte JSON error response. Compression is enabled server-wide with no size threshold. What's the likely outcome?
2. Why is compressing a JPEG image with gzip usually pointless?