Back to blog
Linux & Servers August 25, 2026

Gzip vs Brotli: Compression and Web Performance

Gzip vs Brotli: Compression and Web Performance

At the network edge, reducing payload size is one of the most effective ways to lower latency and save on cloud egress costs. Modern web architectures rely heavily on compression to shrink text-based assets like HTML, CSS, JavaScript, and JSON before transmitting them over HTTP.

While Gzip has been the industry standard for decades, Brotli has emerged as a highly optimized alternative designed specifically for web content. This guide compares Gzip and Brotli compression algorithms, details how to configure them in production, analyzes their CPU-to-bandwidth trade-offs, and shows how to avoid common caching pitfalls.


1. Protocol Negotiation Flow

HTTP compression is negotiated dynamically between the client browser and the server. The exchange operates via headers:

  1. Request: The browser advertises its supported compression algorithms using the Accept-Encoding header:
    Accept-Encoding: br, gzip, deflate
    
  2. Response: The server selects the most efficient algorithm (preferring Brotli (br) over Gzip (gzip)), compresses the response body, and returns the payload with the Content-Encoding header:
    Content-Encoding: br
    Vary: Accept-Encoding
    

The Vary: Accept-Encoding header instructs downstream proxies and CDNs to cache separate representations of the asset based on the browser's supported compression formats, preventing Gzip-only browsers from receiving unreadable Brotli payloads.


2. Gzip vs Brotli Comparison

To select the right compression strategy for each asset type, we must evaluate their architectural properties:

FeatureGzip (DEFLATE)Brotli
Core AlgorithmLZ77 dictionary matching + Huffman codingLZ77 + Huffman coding + 2nd-order context modeling
Static DictionaryNo (generates dictionary dynamically per file)Yes (120KB built-in dictionary of common web words)
Default Quality Range1 (Fastest) to 9 (Most Compressed)0 (Fastest) to 11 (Most Compressed)
Best Target AssetsLegacy browser fallbacksHTML, JS, CSS, SVG, JSON API payloads
Egress ReductionModerate ((15% - 25%) typical)High ((20% - 35%) typical, beats Gzip by (17% - 22%) on JS/CSS)

3. The Math Behind Compression Economics

We define the compressed payload size ((B_c)) using the uncompressed size ((B_u)) and the compression ratio ((R)):

[B_c = B_u \cdot R]

Where the compression ratio is calculated as:

[R = \frac{B_c}{B_u}]

The bandwidth reduction percentage is represented by:

[\text{Reduction} = 1 - R]

At high request volumes, dynamic compression introduces CPU latency overhead. SREs estimate the dynamic compression processing cost ((CPU_{\text{compression}})) on the origin server as:

[CPU_{\text{compression}} = QPS \cdot C_{\text{compress}}(B_u)]

Where (QPS) is queries per second and (C_{\text{compress}}(B_u)) is the CPU time required to compress a payload of size (B_u). If you compress large dynamic JSON payloads at Brotli level 11 on the fly, origin CPU cores will saturate, driving up tail latency ((P_{99})) and increasing server infrastructure costs.


4. Production-Ready Nginx Configuration

To combine Gzip and Brotli efficiently, use this Nginx configuration snippet. It enables dynamic compression for APIs and matches static precompressed assets (prebuilt during your CI/CD build phase) to bypass runtime CPU overhead.

# Enable Gzip Compression
gzip on;
gzip_min_length 1024;
gzip_comp_level 5;
gzip_proxied any;
gzip_vary on;
gzip_types
    text/plain
    text/css
    application/json
    application/javascript
    image/svg+xml;

# Enable Brotli Compression (Requires ngx_brotli module)
brotli on;
brotli_comp_level 4; # Optimized quality setting for dynamic compression
brotli_min_length 1024;
brotli_types
    text/plain
    text/css
    application/json
    application/javascript
    image/svg+xml;

# Match Precompressed Static Files (.br and .gz) if they exist
gzip_static on;
brotli_static on;

5. CLI Verification and Benchmarking

SRE teams verify edge compression behavior using curl to inspect HTTP response headers:

curl -sS -D - \
  -H 'Accept-Encoding: br, gzip' \
  https://pingzoapp.com/assets/app.js \
  -o /dev/null

Reproducible Local Benchmark Script

Create this simple bash script to compare how different encoding requests perform against your endpoints:

#!/usr/bin/env bash
set -euo pipefail

URL="https://pingzoapp.com/assets/app.js"

for encoding in "br" "gzip" "identity"; do
  echo "=== Testing Encoding: $encoding ==="
  curl -sS \
    -H "Accept-Encoding: $encoding" \
    -o "/dev/null" \
    -w 'HTTP Status: %{http_code}\nSize: %{size_download} bytes\nTTFB: %{time_starttransfer}s\nTotal Time: %{time_total}s\n\n' \
    "$URL"
done

[!TIP] Tip (HTTP Header Audit): Use the HTTP Header Checker to verify that your live endpoints are returning the correct Vary: Accept-Encoding and Content-Encoding headers, ensuring your CDN cache is not serving uncompressed assets to modern clients.


6. Troubleshooting Compression Issues

If your page size metrics indicate that compression is failing or inflating latency, execute this step-by-step diagnostic playbook:

  1. Inspect response headers: Verify if the server is returning Content-Encoding: br or gzip when requested via Accept-Encoding.
  2. Verify content types: Ensure the asset's Content-Type is explicitly listed in your web server's gzip_types or brotli_types directives.
  3. Check payload dimensions: Confirm that the uncompressed payload size is greater than your configured minimum threshold (typically 1024 bytes).
  4. Isolate cache validations: Verify if your server is stripping ETag headers or generating weak ETags after compression, which can break 304 Not Modified browser cache validations.
  5. Audit already-compressed assets: Ensure that pre-compressed media formats (like JPEG, WebP, PNG, ZIP, and WOFF2) are explicitly excluded from server-side compression, as recompressing them wastes CPU cycles and can increase final file size.
  6. Measure compression CPU time: Check if origin server CPU cores are bottlenecked. If dynamic Brotli compression is consuming excessive CPU, lower your dynamic quality setting to level 4 or shift compression to the edge CDN.
  7. Identify CDN cache fragmentation: Check if your edge cache keys are normalized. If the CDN is caching separate files for every variation of the Accept-Encoding header, your cache hit ratios will plummet.
  8. Verify security bounds: Disable compression for sensitive API routes that mix user credentials with attacker-controlled inputs to prevent side-channel leaks (like BREACH).
  9. Confirm static assets: Ensure your build process precompresses static JavaScript and CSS files, verifying that Nginx is utilizing the static files rather than dynamically compressing them on the fly.
Try Pingzo Free

Know before your users do

Connect official WhatsApp notification channels, Discord webhooks, Telegram bots, and public status pages. Start in 30 seconds.

Create Free Monitor