DevSwitch.net

Gzip Compression: How HTTP Content Encoding Speeds Up APIs

Illustration of Gzip compression, showing data reduced into smaller blocks before traveling from a server through the Gzip layer to a client.

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.

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
That 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.

Do not gzip responses that mix compression with user secrets in the same context without care. The BREACH attack exploited gzip on pages that reflected user input alongside secret tokens. For most JSON APIs this is not an issue, but be cautious compressing responses that combine attacker-controlled input with sensitive data.

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.

CSS minifier tool reducing file size before gzip compression

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.