Tutorial

Gzip vs Brotli Compression: Configuration and Benchmarks

June 08, 2026

Back to Blog
Managing servers the hard way? Panelica gives you isolated hosting, built-in Docker and AI-assisted management.
Start free

Why Compression Matters for Web Performance

Every byte your server sends to a browser must travel across the network. For a visitor on the other side of the world, that journey involves dozens of network hops, undersea cables, and cellular towers. The larger your response, the longer the journey takes. HTTP compression reduces the size of text-based responses — HTML, CSS, JavaScript, JSON, SVG, and XML — typically by 60-85%, making pages load dramatically faster without any change to the content itself.

Two compression algorithms dominate the web today: Gzip and Brotli. Gzip has been the standard since the late 1990s and is supported by literally every browser and web server in existence. Brotli, developed by Google and released in 2015, achieves significantly better compression ratios, especially for text content. The question is not which one to use — the answer is both. The real question is how to configure them optimally for your specific workload.

This guide provides a comprehensive comparison of Gzip and Brotli, with Nginx and Apache configuration examples, real-world benchmarks on different content types, and guidance on choosing the right compression levels for your server.

How HTTP Compression Works

HTTP compression is a negotiation between the browser and the server. The process works like this:

Browser Request
Accept-Encoding: gzip, br
Server Checks
Supported algorithms
Compress Response
Best mutual algorithm
Send Compressed
Content-Encoding: br
Browser Decodes
Transparent to user
# Browser sends Accept-Encoding header
GET /app.js HTTP/2
Host: example.com
Accept-Encoding: gzip, deflate, br

# Server responds with compressed content
HTTP/2 200 OK
Content-Encoding: br
Vary: Accept-Encoding
Content-Type: application/javascript
Content-Length: 42518
# (Original uncompressed size: 186432 bytes)
The Vary Header Is Essential. When your server compresses responses, it must include Vary: Accept-Encoding in the response. This tells CDNs and proxy caches that different versions of the response exist for different Accept-Encoding values. Without it, a cache might serve a Brotli-compressed response to a client that only supports Gzip, resulting in garbled content.

Gzip: The Universal Standard

Gzip uses the DEFLATE algorithm (a combination of LZ77 and Huffman coding) and has been part of the HTTP standard since HTTP/1.1. It is supported by every browser released in the past 25 years and by every web server, proxy, and CDN.

Gzip Configuration in Nginx

# Nginx Gzip configuration (http block)
gzip on;

# Compression level: 1-9 (1=fastest, 9=smallest)
gzip_comp_level 6;

# Minimum response size to compress
gzip_min_length 256;

# Enable for proxied requests
gzip_proxied any;

# Add Vary header automatically
gzip_vary on;

# MIME types to compress
gzip_types
  text/plain
  text/css
  text/javascript
  text/xml
  application/json
  application/javascript
  application/x-javascript
  application/xml
  application/xml+rss
  application/atom+xml
  application/ld+json
  application/manifest+json
  application/vnd.ms-fontobject
  font/opentype
  font/ttf
  image/svg+xml
  image/x-icon;

# Disable for IE6 (ancient, but just in case)
gzip_disable "msie6";
Do Not Compress Images, Videos, or Already-Compressed Files. JPEG, PNG, WebP, AVIF, MP4, ZIP, and PDF files are already compressed. Attempting to gzip them wastes CPU cycles and can actually make the file slightly larger due to compression overhead. Only compress text-based formats as listed in gzip_types.

Understanding gzip_comp_level

The compression level setting is where the performance trade-off happens. Higher levels produce smaller output but consume more CPU time. Here is the actual impact for a typical JavaScript file:

gzip_comp_levelCompressed SizeCompression RatioCPU TimeRecommendation
168.2 KB63.4%0.8msToo little compression
265.1 KB65.1%1.0ms
362.8 KB66.3%1.3ms
458.4 KB68.7%1.8msGood for high-traffic
556.2 KB69.8%2.5ms
654.8 KB70.6%3.2msBest balance (default)
754.1 KB71.0%5.1ms
853.8 KB71.1%8.4ms
953.6 KB71.2%14.2msDiminishing returns
The Sweet Spot Is Level 6. Notice how levels 7-9 provide virtually identical compression to level 6, but at 2-4x the CPU cost. Level 6 is the default in Nginx for good reason — it achieves 95% of the maximum possible compression with moderate CPU usage. Only go lower (4-5) if your server is CPU-bound under heavy traffic.

Brotli: Better Compression for the Modern Web

Brotli was developed by Google specifically for web content compression. It uses a combination of LZ77, Huffman coding, and a predefined dictionary of common web content patterns (HTML tags, CSS properties, JavaScript keywords). This built-in dictionary gives Brotli a significant advantage over Gzip for web content — it does not need to "learn" common patterns from the data itself because they are already in its dictionary.

Installing the Brotli Module for Nginx

Unlike Gzip, which is built into Nginx by default, Brotli requires a separate module. On most Linux distributions, you can install it as a dynamic module:

# Ubuntu/Debian: Install Brotli module
$ apt install libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static

# Verify module is loaded
$ nginx -V 2>&1 | grep -o 'brotli'
brotli

# If compiling Nginx from source, add:
--add-module=/path/to/ngx_brotli

Brotli Configuration in Nginx

# Nginx Brotli configuration (http block)
brotli on;

# Compression level: 0-11 (0=fastest, 11=smallest)
brotli_comp_level 4;

# Minimum response size to compress
brotli_min_length 256;

# MIME types to compress (same as gzip_types)
brotli_types
  text/plain
  text/css
  text/javascript
  text/xml
  application/json
  application/javascript
  application/x-javascript
  application/xml
  application/xml+rss
  application/atom+xml
  application/ld+json
  application/manifest+json
  application/vnd.ms-fontobject
  font/opentype
  font/ttf
  image/svg+xml
  image/x-icon;

# Serve pre-compressed .br files if available
brotli_static on;

Understanding brotli_comp_level

Brotli has a wider range of compression levels (0-11) than Gzip (1-9). The trade-off between compression ratio and CPU time is more dramatic with Brotli, especially at the highest levels:

brotli_comp_levelCompressed SizeCompression RatioCPU TimeRecommendation
066.4 KB64.4%0.5msBarely better than no compression
158.7 KB68.5%0.7msFast, decent compression
253.2 KB71.4%1.1ms
350.8 KB72.7%1.5ms
448.1 KB74.2%2.8msBest for on-the-fly
546.3 KB75.1%4.5ms
645.2 KB75.7%7.8msGood trade-off
7-943.8-42.1 KB76.5-77.4%15-45msOnly for static pre-compression
1040.5 KB78.3%120msOnly for static pre-compression
1139.2 KB78.9%450msPre-compress only
Never Use brotli_comp_level 11 for Dynamic Content. Level 11 can take 450ms+ to compress a single file. For on-the-fly compression of dynamic responses, level 4 provides an excellent balance — 74% compression with only 2.8ms of CPU time. Reserve levels 7-11 for pre-compressing static assets during your build process.

Apache Configuration

Apache mod_deflate (Gzip)

# Enable mod_deflate
$ a2enmod deflate

# Apache configuration
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE
    text/html
    text/plain
    text/css
    text/javascript
    text/xml
    application/json
    application/javascript
    application/xml
    image/svg+xml
    font/opentype
    font/ttf

  # Compression level (1-9)
  DeflateCompressionLevel 6

  # Skip already-compressed formats
  SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp|avif)$ no-gzip
</IfModule>

Apache mod_brotli

# Enable mod_brotli (Apache 2.4.26+)
$ a2enmod brotli

# Apache configuration
<IfModule mod_brotli.c>
  AddOutputFilterByType BROTLI_COMPRESS
    text/html
    text/plain
    text/css
    text/javascript
    text/xml
    application/json
    application/javascript
    application/xml
    image/svg+xml
    font/opentype
    font/ttf

  # Quality level (0-11)
  BrotliCompressionQuality 4
</IfModule>

Benchmark Results: Gzip vs Brotli

We benchmarked both algorithms against common web content types at their recommended dynamic compression levels (Gzip 6 vs Brotli 4) and Brotli's maximum static compression level (11). All tests used real-world files from popular websites and frameworks.

HTML (WordPress homepage, 52 KB original)

AlgorithmCompressed SizeRatioTime
Gzip level 611.8 KB77.3%1.2ms
Brotli level 49.4 KB81.9%1.8ms
Brotli level 117.9 KB84.8%85ms

CSS (Bootstrap 5, 227 KB original)

AlgorithmCompressed SizeRatioTime
Gzip level 633.4 KB85.3%3.8ms
Brotli level 427.1 KB88.1%4.5ms
Brotli level 1122.8 KB90.0%320ms

JavaScript (React bundle, 186 KB original)

AlgorithmCompressed SizeRatioTime
Gzip level 654.8 KB70.5%3.2ms
Brotli level 448.1 KB74.1%2.8ms
Brotli level 1139.2 KB78.9%450ms

JSON (API response, 84 KB original)

AlgorithmCompressed SizeRatioTime
Gzip level 612.6 KB85.0%1.4ms
Brotli level 410.2 KB87.9%1.6ms
Brotli level 118.1 KB90.4%95ms
Key Finding: Brotli level 4 consistently outperforms Gzip level 6 by 15-20% in compression ratio while using comparable CPU time. For pre-compressed static assets, Brotli 11 provides an additional 25-35% reduction over Gzip 6, but at a massive CPU cost that makes it unsuitable for on-the-fly compression.

Pre-Compression for Static Files

The best of both worlds: compress static assets at maximum quality during your build process, and serve the pre-compressed files directly. This gives you Brotli level 11 compression without any runtime CPU cost.

# Pre-compress files during build
# Brotli (maximum compression)
$ find /var/www/static -type f \( -name "*.css" -o -name "*.js" \
  -o -name "*.html" -o -name "*.svg" -o -name "*.json" \) \
  -exec brotli --best --keep {} \;

# Gzip (for fallback)
$ find /var/www/static -type f \( -name "*.css" -o -name "*.js" \
  -o -name "*.html" -o -name "*.svg" -o -name "*.json" \) \
  -exec gzip -9 --keep {} \;

# Result: three versions of each file
$ ls -la app.*
-rw-r--r-- 186432 app.js
-rw-r--r-- 39218 app.js.br
-rw-r--r-- 53612 app.js.gz

Nginx Configuration for Pre-Compressed Files

# Serve pre-compressed files (zero CPU cost)

# Brotli: serve .br files if they exist
brotli_static on;

# Gzip: serve .gz files if they exist
gzip_static on;

# Priority: Nginx checks for .br first (if browser supports it),
# then .gz, then serves uncompressed original.
# Zero CPU — just file system lookups.

CDN Compression

Most CDNs handle compression automatically. Cloudflare, for example, compresses content at the edge regardless of whether your origin sends compressed responses. However, understanding how CDN compression interacts with your origin configuration prevents surprises:

Cloudflare Compression

Cloudflare always supports Gzip and Brotli at the edge. If your origin sends uncompressed content, Cloudflare compresses it. If your origin sends Gzip-compressed content, Cloudflare may decompress and recompress with Brotli for browsers that support it. For best results, let Cloudflare handle compression and send uncompressed from origin — or pre-compress with Brotli so Cloudflare can serve it directly.

Best Practice

Enable compression on your origin server even when using a CDN. This ensures that cache misses (first request to a PoP) receive compressed responses, and it protects your bandwidth if any requests bypass the CDN. The CDN's compression supplements, not replaces, origin compression.

Testing Compression

# Test Gzip support
$ curl -sI -H "Accept-Encoding: gzip" https://example.com/style.css \
  | grep -i content-encoding
content-encoding: gzip

# Test Brotli support
$ curl -sI -H "Accept-Encoding: br" https://example.com/style.css \
  | grep -i content-encoding
content-encoding: br

# Compare actual transfer sizes
$ curl -so /dev/null -w "Size: %{size_download} bytes\n" \
  -H "Accept-Encoding: gzip" https://example.com/app.js
Size: 54821 bytes

$ curl -so /dev/null -w "Size: %{size_download} bytes\n" \
  -H "Accept-Encoding: br" https://example.com/app.js
Size: 48134 bytes

# No compression (original size)
$ curl -so /dev/null -w "Size: %{size_download} bytes\n" \
  -H "Accept-Encoding: identity" https://example.com/app.js
Size: 186432 bytes

Browser Support

AlgorithmChromeFirefoxSafariEdgeOverall
GzipAllAllAllAll100%
Brotli49+44+11+15+97%+

Brotli is supported by virtually every modern browser. The only browsers without Brotli support are Internet Explorer (all versions) and very old mobile browsers. Since Brotli requires HTTPS (it is only sent over secure connections), any site running HTTPS can safely enable Brotli with Gzip as automatic fallback.

Combined Configuration: The Complete Setup

Here is the recommended configuration that enables both Gzip and Brotli, with pre-compressed file support and optimal compression levels:

# Complete Nginx compression configuration
http {
  # === GZIP ===
  gzip on;
  gzip_comp_level 6;
  gzip_min_length 256;
  gzip_vary on;
  gzip_proxied any;
  gzip_static on; # Serve pre-compressed .gz files
  gzip_types
    text/plain text/css text/javascript text/xml
    application/json application/javascript
    application/xml application/xml+rss
    application/atom+xml application/ld+json
    application/manifest+json
    application/vnd.ms-fontobject
    font/opentype font/ttf
    image/svg+xml image/x-icon;

  # === BROTLI ===
  brotli on;
  brotli_comp_level 4;
  brotli_min_length 256;
  brotli_static on; # Serve pre-compressed .br files
  brotli_types
    text/plain text/css text/javascript text/xml
    application/json application/javascript
    application/xml application/xml+rss
    application/atom+xml application/ld+json
    application/manifest+json
    application/vnd.ms-fontobject
    font/opentype font/ttf
    image/svg+xml image/x-icon;
}
How Nginx Chooses Between Gzip and Brotli: When both are enabled, Nginx checks the browser's Accept-Encoding header. If the browser supports br (Brotli), Nginx uses Brotli. If the browser only supports gzip, Nginx falls back to Gzip. This is automatic — no additional configuration needed. For pre-compressed files, Nginx checks for .br files first, then .gz, then compresses on-the-fly.

When to Use Which

Use Gzip When...

  • You need universal compatibility (100% browser support)
  • Your server cannot install the Brotli module
  • You are behind a proxy/CDN that does not forward Brotli
  • HTTP-only sites (Brotli requires HTTPS)

Use Brotli When...

  • Your site uses HTTPS (required for Brotli)
  • You want the best compression ratios
  • You serve large JavaScript/CSS bundles
  • Mobile performance is a priority (smaller = faster)
Panelica's Compression Configuration: Panelica configures both Gzip and Brotli compression in Nginx for all domains, with optimized compression levels that balance file size reduction with CPU usage. Every domain provisioned through the panel automatically receives both compression algorithms — Brotli at level 4 for HTTPS domains and Gzip at level 6 as universal fallback — without any manual configuration required.

Summary: Quick Reference

SettingGzipBrotli
Dynamic compression level64
Static pre-compression level911
Minimum response size256 bytes256 bytes
Typical HTML compression77%82%
Typical CSS compression85%88%
Typical JS compression71%74%
Browser support100%97%+
Requires HTTPSNoYes

The bottom line: enable both. Gzip provides universal coverage, Brotli provides superior compression for the 97%+ of browsers that support it. With pre-compression for static assets and on-the-fly compression for dynamic content, your server delivers the smallest possible responses to every visitor regardless of their browser. The bandwidth savings pay for themselves in faster load times, lower hosting costs, and happier users.

Security-first hosting panel

Run your servers on a modern panel.

Panelica is a modern, security-first hosting panel — isolated services, built-in Docker and AI-assisted management, with one-click migration from any panel.

Zero-downtime migration Fully isolated services Cancel anytime
Share:
Atomic updates included.