...

Compression level and CPU load: How Gzip and Brotli affect hosting performance

I show how the selected Compression level changes the CPU load of web servers and how Gzip and Brotli have a measurable impact on hosting performance. With clear settings I reduce the Server load noticeable without compromising on loading times.

Key points

  • CPU costs increase faster with higher levels than the savings in file size.
  • Gzip 4-6 is often the best compromise for dynamic content.
  • Breadstick delivers smaller files, but requires more CPU at high levels.
  • Precompression shifts the computing load from the request time to the build process.
  • Monitoring makes expensive compression paths immediately visible.

Why compression on the server costs CPU

HTTP compression often reduces text assets by 50-80 %, but every kilobyte saved comes from additional Calculation work. Modern browsers decompress effortlessly, the bottleneck is the server, which compresses per request. Brotli uses larger search windows and dictionaries, which is significantly more efficient at higher levels. CPU time binds. Gzip works more simply, but is also surprisingly expensive at high levels. Anyone who understands the connections and Configure HTTP compression reduces peak loads and improves response times.

What I don't compress: Binary formats and minimum sizes

Not every answer benefits from compression. Many binary formats are already efficient or even worse to compress, while the CPU overhead still arises. I save a lot of computing time if I specifically exclude the following categories and set a minimum size for compression to take effect.

  • Already compressed mediaJPEG/JPG, PNG, WebP, AVIF, MP4/WEBM, MP3/AAC, PDF (often), ZIP/GZ/BR.
  • Small answersCompression is rarely worthwhile below ~1-2 KB, as header overhead and latency dominate.
  • Binary downloadsInstallers, archives, data blobs - here compression attempts only cause CPU costs.

I therefore define a clear positive list of MIME types (text, JSON, JavaScript, CSS, SVG, XML) and set a minimum size. These two levers avoid useless work and stabilize the throughput under load.

Configure MIME filters and thresholds cleanly

A finely granulated selection is practical: I consistently compress text formats, but I differentiate between highly dynamic endpoints (e.g. API-JSON) and less frequently changed pages (e.g. HTML with low personalization). In addition, for each MIME type I create a Minimum length to be compressed to leave short responses unpacked. This mix prevents small 204/304 responses or mini JSONs from running through the compression pipeline unnecessarily.

Gzip: Medium levels deliver the best mix of size and CPU

Gzip offers nine levels, from 1 to 9, and the CPU curve increases disproportionately from level 6, while the Savings only increases slightly with the file size. For a JavaScript file around 1 MB, for example, compression times are roughly around 50 ms (level 3) and around 300 ms (level 9) - the gain shrinks, the waiting time increases. In highly frequented setups, this effect scales over many requests per second and eats up a high proportion of the CPU resources. Gzip 4-6 therefore pays off for dynamic responses, while 7-9 usually only uses a few smaller files but much more CPU. I reduce TTFB noticeably when I lower excessive Gzip levels.

The following table summarizes typical tendencies so that I can choose the right level with confidence and Hosting performance stable.

Algorithm Level Size reduction (typ.) CPU time (relative) Typical use
Gzip 1-3 50-65 % Low Very dynamic content
Gzip 4-6 60-75 % Medium Standard for dynamic responses
Gzip 7-9 62-77 % High Special cases, rarely useful on the fly
Breadstick 3-5 65-82 % Medium-high Dynamic content with a focus on size
Breadstick 9-11 68-85 % Very high Pre-compressed, static assets

Brotli: Greater savings factor, but higher CPU at high levels

Brotli usually squeezes text files a little smaller than Gzip, but each additional level increases the computing time on. Even medium levels generate very good rates, while high levels quickly slow down on-the-fly compression. For dynamic content, I therefore use levels 3-5 to achieve a stable ratio between file size and compression rate. Latency to keep. I compress static files in the build with level 9-11, because the effort is only required once. If you want to see the differences in compact form, you can find them at Brotli vs Gzip in broad juxtaposition.

Diminishing returns: More levels, less benefit per CPU second

If the compression level increases from 1 to 5, I quickly gain significantly smaller files, but from this range the yield per additional CPU second becomes thinner. The jump from Gzip 5 to 9 or from Brotli 5 to 9 often only brings a few percentage points, but devours noticeably Processor time. In productive environments, this has an impact on TTFB and throughput. I therefore pay attention to hot paths in profilers first and reduce expensive compression levels before I buy more hardware. This is how I secure Scalability and keep costs under control.

Precompression for static assets: calculate once, benefit permanently

CSS, JS, SVG and web fonts rarely change, so I compress them with high Brotli levels before deployment. The delivery then falls back on .br or .gz files, without on-the-fly CPU to consume. CDNs and modern web servers recognize the correct type based on accept encoding and deliver the appropriate variant directly. This allows me to shift computing time to the build, alleviate load peaks and keep response times stable. The result is constant Loading times even under high load.

When high levels still make sense

There are exceptions where I deliberately use very high compression levels: for rarely updated, large static assets with a high reach (e.g. framework bundles), for downloads that are cached for an extremely long time or for content that is accessed by many geographically distributed users. The one-off build effort is hardly significant, while the additional percentage points saved significantly reduce bandwidth and CDN costs. The prerequisite is that these files not are compressed on-the-fly and the server delivers the pre-generated .br/.gz variants directly.

Customized levels for dynamic responses

For HTML, API-JSON or personalized content, my setting aims for a robust ratio of compression rate and CPU load. I usually set Gzip to level 4-6 and keep Brotli at 3-5 so that latencies remain predictable. As soon as profilers show that compression dominates, I lower the level and check the effect on TTFB. In many cases, the page size remains almost the same, while the Response time decreases measurably. This simple lever often helps more than upgrading the instance size.

Streaming and small answers: flush, chunking, SSE

For streamed responses (server-sent events, long polling responses, incremental HTML), I take into account that compression Buffer uses. Too aggressive buffering delays the first bytes, too frequent flushing makes compression inefficient. I therefore choose moderate buffer sizes and deactivate compression for pure event streams where latency is more important than size. For very small answers I avoid compression completely - the overheads of headers and context initialization are more expensive than the benefits.

Combination of Gzip and Brotli: Maximum compatibility

I activate Brotli for modern browsers and leave Gzip as a fallback so that older clients are served reliably. Negotiation takes place via accept encoding, while the server delivers compressed files depending on availability. This way I achieve small files for new browsers and constant Compatibility for old environments. If you also set the cache control and Vary header correctly, you avoid computing work in subsequent requests. This combination results in a very efficient Delivery with low CPU load.

Caching and Vary: avoid 304, ETag and double-compress

For caches to work correctly, I set the Vary: Accept-Encoding-header consistently and make sure that compressed and uncompressed variants are stored separately. Otherwise, I run the risk of a cache delivering a Gzip file to a client without Gzip support. I also check that 304 responses (Not Modified) do not trigger compression - the server should remain lean here. A common error is Double-Compress: Upstreams deliver already compressed, the edge server compresses again. I control content encoding and prevent duplicate work with clean rules. ETags and file names with hash (e.g. app.abc123.js) facilitate cache coherence and make pre-compression particularly effective.

Tuning in hosting environments with many projects

In multi-tenant setups, small inefficiencies add up to a large one CPU guzzler. I start with measurements: Percentage of CPU time in compression routines, TTFB, throughput and cache hit rates. Flamegraphs quickly reveal when Gzip or Brotli consume too much. I then adjust the levels step by step, check the effects and validate the results with load tests. I repeat this cycle regularly in order to achieve long-term Stability guarantee.

Measure, test, readjust: A pragmatic procedure

I first document the actual status and target values, then I gradually reduce compression levels that are too expensive. Typically, I switch from Gzip 7-9 to 5-6 or from Brotli 8-9 to 4-5, which immediately frees up CPU time. I then compare TTFB, latency P95 and Throughput before and after the change. If metrics show no loss in size, I leave it at the more favorable level. This routine keeps systems fast and scalable.

Safety aspects: Reducing BREACH risks pragmatically

Compression and safety are linked: Are secret tokens (e.g. CSRF, session fragments) are mixed together with user-controlled data in a compressed response, attacks that draw conclusions from size changes are theoretically possible. In practice, I avoid this by keeping sensitive content out of such responses, deactivating compression on specific endpoints or decoupling tokens (separate cookies, no reflection in HTML). For particularly critical paths, it is better not to use on-the-fly compression than to take the risk.

Influence on costs and scaling

Less CPU time per request increases the number of requests per instance and creates space for peaks. This reduces operating and hosting costs in euros, without the User experience to be jeopardized. At the same time, the risk of timeouts occurring under load is reduced. I save budget in the right place and invest specifically in caching or faster storage systems. This keeps the platform economical and highly reactive.

HTTP/2/HTTP/3 and TLS: Classification

With HTTP/2 and HTTP/3, I benefit from header compression and multiplexing, but this is no substitute for body compression. Especially with many small files, the overhead is reduced by split connections and prioritization, but text content remains the dominant factor. Even TLS does little to change this: encryption takes place after compression. I therefore continue to base my tuning on the Body sizes, parallelism and compression levels and use the newer protocols as a supplement, not a replacement.

Hosting selection and setup: Hardware, server, formats

Strong single-core performance, up-to-date web server builds and sensible defaults for Gzip/Brotli make tuning easier. Providers with clean pre-configuration save me time and give me reserves for app logic. In addition to text assets, I also pay attention to media formats and consider modern image paths - a quick start is the comparison WebP vs AVIF. In this way, I additionally reduce overall traffic and relieve the CPU indirectly, because fewer bytes have to be sent over the line. Hosting with powerful cores provides the necessary performance for demanding projects. Performance, so that compression, caching and app load remain in balance.

Error patterns and troubleshooting in practice

I can quickly identify typical problems with simple checks. Does the server deliver Content encodinggzip/br twice? Then it is usually double-compress. Voices Vary-headers and cache keys, a proxy can forward compressed responses to incompatible clients. In the case of strange TTFB peaks, I check whether the minimum size is too low and too many small responses are compressed. I also look at CPU profiles: If compression dominates in Flamegraphs, I reduce levels or outsource work to precompression. I also take a look at error pages is worthwhile - compression is often unnecessary here and blocks valuable CPU in exceptional situations.

Action plan in short form

I enable compression for all text-based assets and start with Gzip 4-6 for dynamic content and Brotli 3-5 for CPU load and file size. I compress static files in the build with high Brotli levels so that the request time remains free of unnecessary computing work. I then measure TTFB, latency P95 and CPU shares and reduce levels if compression takes too much time. For maximum compatibility, I rely on Brotli for modern clients and Gzip as a reliable Fallback. This process delivers smaller files, more stable response times and more scope per server instance - a noticeable advantage for speed and cost-effectiveness.

Current articles