Gzip level 9 and the price of the last few bytes
A close reading of ASAMB compression results and the difference between dynamic-response and precompressed-asset decisions.
Compression settings are often inherited from a server example and treated as a quality dial: a higher number appears to mean a better result. The current ASAMB run shows why that mental model is incomplete.
The relevant decision is not “which level creates the smallest file?” It is “where is compression performed, how often is the result reused and what is the incremental cost of each additional byte saved?”
The measured trade-off
On the current fixture, level 1 produced 9,532 bytes bytes at 380.10 µs. Level 6 produced 6,784 bytes bytes at 927.82 µs. Level 9 reached 6,369 bytes bytes at 2.49 ms.
Moving from level 6 to level 9 saved 415 additional bytes in this fixture. The median compression time increased by roughly 2.68×. That is a diminishing-return pattern, not a universal verdict against level 9.
The smallest artifact won the size column. It did not automatically win the delivery decision.
Dynamic responses pay repeatedly
When an uncached response is compressed inside the request path, the server pays the compression cost each time. Under concurrency, that work competes with application code, TLS, database activity and other requests.
A middle level can be a rational default when it captures most of the available size reduction while avoiding the highest CPU cost. The exact level should be tested on representative HTML, JSON, CSS and JavaScript rather than a single generic fixture.
Static assets can make a different bargain
A build pipeline can compress a static asset once and serve the result thousands of times. In that case, additional build-time CPU may be almost free relative to recurring network savings. The same level that is wasteful for dynamic JSON might be reasonable for a versioned JavaScript bundle.
CDNs add another layer: an edge may compress, cache or negotiate content independently. Origin-side microbenchmarks cannot predict cache hit rates or regional transfer performance.
Raw bytes are not transferred bytes
Headers, TLS records, transport behavior and cache reuse affect actual network cost. Small raw differences may disappear inside protocol overhead, while larger repeated responses can accumulate meaningful savings.
Measure real transfer size with the production delivery stack before converting a local gzip result into a bandwidth forecast.
A deployment checklist
The purpose of this checklist is not to force one gzip level. It is to ensure that the selected level is tied to the place where the work occurs and the number of times the result will be reused.
- Separate policies for dynamic responses and precompressed static assets.
- Measure representative content, not only highly repetitive strings.
- Record compression time and output bytes together.
- Verify CDN and reverse-proxy behavior before tuning the application layer.
- Load-test under concurrency when compression runs on the request path.