Gzip has been compressing web content since 1992. It’s good. It’s everywhere. And it’s showing its age. Brotli is its modern replacement, developed by Google, standardised in 2016 (RFC 7932), and now supported by every browser that matters. On typical web content, Brotli achieves 15–26% better compression than gzip at comparable speeds. Smaller files mean faster page loads, lower bandwidth costs, and better Core Web Vitals scores. This guide sets up NGINX Brotli compression the right way, including pre-compressing static assets so NGINX Brotli serves them with zero per-request CPU. See the Brotli reference implementation for the format itself.

The myguard APT repository ships a native Brotli dynamic module for both NGINX and Angie, install it with one apt command, load it with one config line, and your server starts serving Brotli to every browser that supports it.
NGINX Brotli vs gzip: the actual numbers
Brotli uses a combination of LZ77, Huffman coding, and a 2nd-order context modeling that gzip doesn’t have. The practical result:
| Content type | Gzip (level 6) | Brotli (level 6) | Brotli advantage |
|---|---|---|---|
| HTML | 68% reduction | 78% reduction | +15% |
| CSS | 72% reduction | 84% reduction | +21% |
| JavaScript | 67% reduction | 80% reduction | +19% |
| JSON API response | 71% reduction | 83% reduction | +17% |
| SVG | 74% reduction | 86% reduction | +19% |
Brotli level 11 (maximum) achieves 20–26% better compression than gzip, but is extremely slow to encode, suitable only for pre-compressed static assets, not on-the-fly. Level 4–6 is the sweet spot for on-the-fly dynamic compression: better than gzip, fast enough for real-time use.
Step 1, Install the Brotli Module
# Add the myguard repository if not already done
wget https://raw.githubusercontent.com/eilandert/deb.myguard.nl/main/myguard.deb
dpkg -i myguard.deb
apt-get update
# Install NGINX with the Brotli module
apt-get install nginx libnginx-mod-http-brotli
# Or for Angie:
apt-get install angie angie-module-http-brotli
New to the myguard repository? Follow the two-minute setup guide.
Step 2, Load the Module
The myguard package installs a load snippet automatically. Verify it’s in place:
ls /etc/nginx/modules-enabled/ | grep brotli
# Should show: 50-mod-http-brotli-filter.conf and 50-mod-http-brotli-static.conf
If not present, add to the top of nginx.conf (before the http block):
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;
Step 3, Configure Brotli
Add this inside your http block in nginx.conf:
http {
# Brotli dynamic compression (on-the-fly)
brotli on;
brotli_comp_level 6; # 0-11, sweet spot is 4-6
brotli_min_length 256; # Don't compress tiny responses
brotli_types
text/plain
text/css
text/javascript
text/xml
text/x-component
application/javascript
application/json
application/xml
application/rss+xml
application/atom+xml
application/vnd.ms-fontobject
image/svg+xml
font/truetype
font/opentype;
# Brotli static files (serve pre-compressed .br files)
brotli_static on;
# Keep gzip as fallback for browsers that don't support Brotli
gzip on;
gzip_comp_level 6;
gzip_min_length 256;
gzip_vary on;
gzip_types
text/plain text/css text/javascript application/javascript
application/json application/xml image/svg+xml font/opentype;
}
Step 4, Test and Reload
nginx -t && systemctl reload nginx
Verify Brotli is working:
# curl with Brotli accept header
curl -H 'Accept-Encoding: br,gzip' -I https://example.com
# Look for: Content-Encoding: br
# Check Chrome DevTools: Network tab > select a request > Response Headers > Content-Encoding: br
Pre-Compressed Static Assets (Best Performance)
For static files that don’t change (CSS, JS, fonts), pre-compress them at build time with level 11 and let NGINX serve the .br files directly. This gives maximum compression with zero runtime CPU cost:
# Pre-compress all JS and CSS files in your web root
find /var/www/html -name '*.js' -o -name '*.css' | while read f; do
brotli -Z -f "$f" -o "${f}.br" # -Z = level 11
gzip -9 -k -f "$f" # -k = keep original, for fallback
done
With brotli_static on in your NGINX config, when a browser requests app.js with Accept-Encoding: br, NGINX automatically serves app.js.br without doing any runtime compression. Zero CPU, maximum compression.
# Install the brotli CLI tool
apt-get install brotli
Brotli for WordPress
WordPress sites benefit significantly from Brotli because WordPress generates a lot of HTML, CSS, and JavaScript. The main caveat: PHP responses are compressed dynamically, so set a sane compression level (4–6) to avoid adding more than ~1ms of CPU time per request.
Typical page size reduction for a WordPress homepage:
- Uncompressed HTML: ~180KB
- Gzip level 6: ~28KB
- Brotli level 6: ~23KB
- Brotli level 11 (pre-compressed): ~19KB
The 5KB difference between gzip and Brotli level 6 saves ~40ms on a typical 4G connection. Across thousands of page views, that’s meaningful for Core Web Vitals.
Brotli + zstd: Running Both
The myguard repository also ships a zstd NGINX module. zstd excels at server-side API compression (faster decode, great for JSON) while Brotli excels at browser-facing content (better compression ratio). Run both:
apt-get install libnginx-mod-http-brotli libnginx-mod-http-zstd
# In http block:
brotli on; # For browsers (HTML, CSS, JS)
brotli_types text/html text/css application/javascript image/svg+xml;
zstd on; # For API clients that support it
zstd_types application/json application/x-ndjson;
zstd_comp_level 3;
Frequently Asked Questions
Related Posts
- zstd NGINX Module: What It Does and 22 Bug Fixes: the other modern compression option, great for API workloads
- NGINX Dynamic Modules Overview: Brotli is one of 50+ available modules
- NGINX Performance and Security Expert Guide: full performance tuning guide including compression strategy
- NGINX vs Apache Benchmark 2026: performance comparison including compression overhead
- How to Add the myguard APT Repository: where the Brotli module comes from