Transfer-Encoding Reference

chunked, gzip, deflate, br transfer-encoding values with combination rules.

Reference for HTTP Transfer-Encoding and Content-Encoding values covering chunked transfer, gzip, deflate, br and zstd compression, ordering rules and HTTP/2 differences. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

What is the difference between Transfer-Encoding and Content-Encoding?

Content-Encoding is an end-to-end property of the representation: the body is compressed and stays compressed until the client decodes it. Transfer-Encoding is a hop-by-hop framing applied for one connection — chunked is its main use. Use Content-Encoding for compression in practice.

Framing versus compression — two headers people conflate

Transfer-Encoding and Content-Encoding look similar but mean different things. One frames the message for a single connection hop (chunked); the other compresses the representation end-to-end (gzip, br). Confusing them leads to double-compression bugs and caches serving undecodable bodies. This reference sorts every coding value into the right layer.

How it works

  • Content-Encoding is end-to-end. The body is compressed (gzip, br, deflate, zstd) and a cache stores it that way; the client decodes it. It is negotiated via Accept-Encoding and recorded in Vary.
  • Transfer-Encoding is hop-by-hop, applied for one connection then stripped by the next. Its dominant value is chunked, which streams a body of unknown length as size-prefixed chunks ending in a zero-length chunk:
Transfer-Encoding: chunked

7\r\n
Mozilla\r\n
0\r\n
\r\n

Multiple codings are applied left-to-right and decoded right-to-left, with chunked always last in a Transfer-Encoding list. In HTTP/2 and HTTP/3 the binary framing replaces all of this, so Transfer-Encoding is prohibited there.

Coding values quick reference

CodingHeaderTypeNotes
chunkedTransfer-EncodingFramingOnly used in HTTP/1.1; forbidden in HTTP/2+
gzipContent-EncodingCompressionMost widely supported; uses DEFLATE with gzip wrapper
brContent-EncodingCompressionBrotli; typically 15-25% smaller than gzip
deflateContent-EncodingCompressionAmbiguous in practice (zlib vs raw DEFLATE); avoid
zstdContent-EncodingCompressionZstandard; fast decompression, growing browser support
identityContent-EncodingNo-opExplicit “no encoding applied” signal

Why HTTP/2 removed chunked

Chunked transfer-encoding exists to solve an HTTP/1.1 problem: the server did not know the response body size in advance, so it could not set Content-Length. Chunked framing let the server stream data of unknown length by prefixing each chunk with its size.

HTTP/2 solved this differently. Its binary framing layer sends data as typed frames, and the connection’s own framing mechanism handles body length without needing a special transfer-coding. The Transfer-Encoding: chunked header is therefore prohibited in HTTP/2 — sending it is a protocol error that causes browsers to close the connection or trigger an error response.

This is a common source of bugs when migrating from HTTP/1.1 to HTTP/2 or when a reverse proxy rewrites the connection. The proxy terminates the HTTP/1.1 chunked connection from the backend but must not pass the Transfer-Encoding header on to the HTTP/2 client.

Choosing between gzip, br, and zstd

Modern browsers support all three compression codings, but the right choice depends on your deployment:

  • gzip is the safest choice for broad compatibility. All HTTP clients and CDNs support it. Use it for any public-facing API or when CDN support matters.
  • br (Brotli) typically achieves better compression ratios than gzip for text content (HTML, CSS, JSON) but is slower to compress at high compression levels. It is ideal for static assets served from a CDN that pre-compresses.
  • zstd has very fast decompression and good compression ratios. It has growing browser support and is well-suited to high-throughput APIs. It is also the preferred codec for many server-to-server streaming APIs where both ends are known to support it.

For dynamic responses, gzip is still the standard. For static assets, br at a high compression level (pre-computed offline) reduces transfer size most effectively. For internal service-to-service communication, zstd is worth benchmarking.

Tips and notes

  • Compress with Content-Encoding, not Transfer-Encoding, in practice.
  • Never set both a Content-Length and Transfer-Encoding: chunked — they are mutually exclusive in HTTP/1.1.
  • Do not double-compress: a body already compressed with br served with gzip Content-Encoding is corrupt and undecodable by the client.
  • Trailers ride after the final chunk; advertise them with the TE: trailers request header.
  • Set Vary: Accept-Encoding on compressed responses so caches serve the correct encoding to clients that do not support compression.