Gzip compression is a method for shrinking the size of files sent over the web by finding and removing repeated patterns in the data before it travels from a server to a browser or API client. When a server applies gzip, an HTML page, JSON response, or CSS file that started at 200 KB might arrive as 40 KB, which means less data crosses the network and pages and API calls load noticeably faster. It works through the HTTP
Content-Encoding
header, and nearly every browser and HTTP client made in the last two decades supports it automatically.
Content Table
How gzip compression works
Gzip is built on the DEFLATE algorithm, which combines two techniques to squeeze data down:
- LZ77 matching: it scans for repeated strings of bytes and replaces later copies with a short pointer back to the earlier one. Text with repetition (HTML tags, JSON keys, whitespace) compresses extremely well.
- Huffman coding: it assigns shorter bit sequences to the most common bytes and longer ones to rare bytes, so frequent characters take up less space.
Because web content is full of repetition (think of a JSON array where every object has the same "id", "name", and "status" keys), gzip finds a lot to eliminate. The format itself dates back to 1992 and is defined in
RFC 1952.
The HTTP handshake behind compression
Compression only happens when both sides agree on it, and that negotiation is quick. The client tells the server what it can decode, and the server responds with what it actually used.
-
The client sends a request header:
Accept-Encoding: gzip, deflate, br - The server picks a supported method and compresses the body
-
The server replies with:
Content-Encoding: gzip - The client sees that header and decompresses the body before using it
Request:
GET /api/products HTTP/1.1
Accept-Encoding: gzip
Response:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: gzip
Vary: Accept-Encoding
Vary: Accept-Encoding
header matters. It tells caches to store separate versions for compressed and uncompressed clients, so a proxy never hands a gzipped body to a client that cannot read it.
If you want to understand how servers signal success, redirects, and errors around these responses, our guide to HTTP status codes and what each number means covers the codes you will see alongside these headers.
Content-Encoding vs Transfer-Encoding
People mix these two up constantly, but they answer different questions.
| Header | What it means | Applies to |
|---|---|---|
| Content-Encoding | The body itself is compressed and stays that way end to end | The actual resource (a file, JSON, HTML) |
| Transfer-Encoding | Encoding applied only for this hop of the connection (like chunked transfer) | The message on a single connection, not the stored resource |
In practice, almost everyone uses
Content-Encoding: gzip
for HTTP compression.
Transfer-Encoding: gzip
exists in the HTTP/1.1 spec, but browsers do not support it at all, and HTTP/2 and HTTP/3 do not use Transfer-Encoding, so do not rely on it for compression. When someone talks about "http compression" or "http content-encoding" for websites and APIs, they mean
Content-Encoding.
What compression ratio to expect
Compression ratio is how much smaller the file gets. A ratio of 4:1 means the compressed file is a quarter of the original size. What you get depends almost entirely on the content type.
| Content type | Typical size reduction |
|---|---|
| HTML, CSS, JavaScript | 70% to 90% smaller |
| JSON and XML API responses | 60% to 85% smaller |
| Plain text and SVG | 60% to 80% smaller |
| JPEG, PNG, MP4, ZIP | Almost nothing (already compressed) |
Gzip also lets you pick a level from 1 (fastest, least compression) to 9 (slowest, most compression). Most servers default to somewhere in the middle (level 6) because level 9 uses noticeably more CPU for only a small extra size gain. If your server compresses responses on the fly for every request, that CPU tradeoff is real.
Why gzip matters for APIs
API responses are often JSON, and JSON is one of the most compressible formats around because of all the repeated keys and structure. A paginated response returning 100 records with identical field names can shrink dramatically.
- Faster responses on slow networks: mobile clients on 3G or congested connections feel the biggest improvement.
- Lower bandwidth bills: if you serve millions of API calls, cutting payload size 70% cuts egress cost too.
- Better perceived speed: smaller bodies mean fewer network round trips to receive the full response.
Gzip pairs well with other efficiency tools. Combine it with proper caching using ETags to improve cache performance so clients skip re-downloading unchanged data, and with API rate limiting to keep traffic predictable. Compression reduces the cost of each successful response; caching and rate limiting reduce how many responses you send at all.
Browser support and alternatives
Browser support for gzip is effectively universal. Every version of Chrome, Firefox, Safari, and Edge, plus command-line tools like
curl
and libraries in Python, Node, Java, and Go, send
Accept-Encoding: gzip
and decode it without any extra setup.
The main modern alternative is
Brotli
(Content-Encoding: br), developed by Google. Brotli usually compresses text 10% to 20% smaller than gzip and decompresses about as fast, but its highest levels compress much more slowly, so static files are usually pre-compressed with Brotli ahead of time while dynamic responses use a middle level on the fly. All current browsers support it, but only over HTTPS; on plain HTTP they do not advertise br. Many servers now offer both and pick Brotli when the client advertises
br in Accept-Encoding, falling back to gzip otherwise. You can read the details in the
MDN Content-Encoding reference.
The newest option is Zstandard (Content-Encoding: zstd), which compresses about as well as Brotli at much higher speeds. Chromium-based browsers (Chrome, Edge, Opera) and Firefox support it, but at the time of writing Safari does not, so keep Brotli and gzip as fallbacks.
When gzip does not help
Compression is not free, and there are cases where it wastes CPU or even backfires:
- Already-compressed files: JPEGs, PNGs, MP4 video, and ZIP archives have no repetition left to squeeze. Compressing them adds CPU cost and can make them slightly larger.
- Tiny responses: gzip adds about 18 bytes of overhead. For a 40-byte response, compression makes it bigger, so most servers skip files under roughly 1 KB.
- Extremely high request rates with on-the-fly compression: if CPU is your bottleneck, pre-compressing static assets once (rather than per request) is smarter.
The fix for most of these is configuration: tell your server which MIME types to compress (text, JSON, JavaScript, CSS, SVG) and set a minimum size threshold. Done right, gzip is one of the cheapest performance wins available, often a single line of server config for a double-digit percentage speedup.
Shrink CSS before gzip even runs
Gzip compresses smaller files faster, and minifying first removes whitespace and comments so http compression has less raw data to process. Clean your stylesheets in seconds.
Try the free CSS minifier →
The decoding side is automatic because browsers and HTTP clients always send
Accept-Encoding: gzip
and decompress responses on their own. The encoding side is not automatic. You must enable gzip in your web server or CDN and tell it which content types to compress.
For text and JSON, Brotli usually produces files 10% to 20% smaller than gzip and decompresses about as fast, though its highest compression levels are much slower, so it is the better choice when both client and server support it. Gzip remains the reliable fallback because its support is completely universal, so most setups offer both.
Yes, but only for already-compressed or very small files. Gzip adds roughly 18 bytes of overhead, and formats like JPEG, PNG, and MP4 have no repeatable patterns left, so compressing them wastes CPU and can slightly increase size. Servers usually skip these by MIME type and a minimum size threshold.
Content-Encoding means the resource body itself is compressed and stays that way from server to client. Transfer-Encoding applies only to a single connection hop, like chunked transfer. For compressing websites and APIs you almost always use
Content-Encoding: gzip, not Transfer-Encoding.
Levels run from 1 (fastest) to 9 (smallest output). Level 6 is the common default because level 9 spends a lot more CPU for only a marginal size gain. If you compress static files once ahead of time, level 9 is fine. If you compress dynamically per request, stick near level 6.