Gzip & Brotli Compression: Reducing Transfer Size
Compressing text-based content (HTML, CSS, JS, JSON) reduces network transfer by 60–80% and dramatically improves page load times. Nginx supports both Gzip and Brotli compression.
Gzip vs Brotli
| Item | Gzip | Brotli |
|---|---|---|
| Standard | RFC 1952 (1996) | RFC 7932 (2016) |
| Compression ratio | Baseline | ~15–25% better |
| Speed | Fast | Levels 1–4 are similar; high levels are slower |
| Browser support | All browsers | Modern browsers (not IE) |
| Requires HTTPS | No | Browsers only request it over HTTPS |
| Best use | General purpose | Pre-compressing static files |
Nginx Gzip Configuration
# /etc/nginx/nginx.conf — http block
http {
# Enable Gzip
gzip on;
# Minimum file size (smaller files are not worth compressing)
gzip_min_length 1024; # skip files under 1 KB
# Compression level: 1 (fast, low ratio) – 9 (slow, high ratio)
# 5–6 is the CPU-efficiency sweet spot
gzip_comp_level 5;
# MIME types to compress (images/video are already compressed — skip them)
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
application/rss+xml
image/svg+xml
font/ttf
font/woff
font/woff2;
# Compress responses forwarded through a proxy
gzip_proxied any;
# Add Vary: Accept-Encoding (helps cache distinguish compressed vs plain)
gzip_vary on;
# Disable for IE6 (buggy Gzip support)
gzip_disable "MSIE [1-6]\.";
# Compression buffer
gzip_buffers 32 4k;
# Apply compression even for HTTP/1.0 requests
gzip_http_version 1.0;
}
Nginx Brotli Configuration
Brotli requires a separate module. On Ubuntu install libnginx-mod-http-brotli-filter.
# Ubuntu
sudo apt install libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static
# Or compile from source
# --add-module=/path/to/ngx_brotli
# /etc/nginx/nginx.conf — http block
http {
# Dynamic Brotli compression
brotli on;
brotli_comp_level 4; # 0–11, levels 4–6 recommended (CPU efficient)
brotli_min_length 1024;
brotli_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml;
}
Pre-compression — Best Performance
For static files, compress at deploy time rather than per-request. This eliminates CPU cost entirely.
# Pre-compress during the deployment pipeline
gzip -9 -k /var/www/html/static/app.js # creates app.js.gz
brotli -9 -k /var/www/html/static/app.js # creates app.js.br
# Nginx automatically picks the pre-compressed file
server {
location ~* \.(css|js|html|json|svg)$ {
root /var/www/html;
brotli_static on; # serve app.js.br if it exists
gzip_static on; # serve app.js.gz if it exists
}
}
Apache Gzip Configuration (mod_deflate)
# Enable mod_deflate
sudo a2enmod deflate
# /etc/apache2/conf-available/compression.conf
<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
DeflateCompressionLevel 5
AddOutputFilterByType DEFLATE text/html text/css text/javascript
AddOutputFilterByType DEFLATE application/javascript application/json
AddOutputFilterByType DEFLATE application/xml image/svg+xml
# Add Vary header for cache differentiation
Header append Vary Accept-Encoding
# Skip already-compressed files
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png|zip|gz|bz2|woff2)$ no-gzip dont-vary
# Legacy browser handling
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
</IfModule>
Measuring Compression Effectiveness
# Compare size before and after
curl -s -H "Accept-Encoding: gzip" https://example.com/api/products \
-o /dev/null -w "Size: %{size_download} bytes, Time: %{time_total}s\n"
curl -s https://example.com/api/products \
-o /dev/null -w "Size: %{size_download} bytes, Time: %{time_total}s\n"
# Check compression headers
curl -I -H "Accept-Encoding: gzip, br" https://example.com/static/app.js
# Content-Encoding: br ← Brotli in use
# Content-Encoding: gzip ← Gzip in use
# Measure compression ratio
echo "Original size:"
wc -c /var/www/html/static/app.js
echo "Gzip size:"
gzip -c -9 /var/www/html/static/app.js | wc -c
echo "Brotli size:"
brotli -c -9 /var/www/html/static/app.js | wc -c
What to Compress — and What to Skip
# DO NOT compress these — already compressed:
# JPEG, PNG, WebP, AVIF — compressed images
# ZIP, GZ, BR, WOFF2 — compressed files
# MP4, WebM — compressed video
# Encrypted data — compression has no effect
# DO compress these:
# HTML: 50–70% savings
# CSS: 60–80% savings
# JavaScript: 60–80% savings
# JSON APIs: 60–90% savings (more repetition = better ratio)
# SVG: 70–90% savings (XML-based)
Performance Tuning Tips
http {
gzip_comp_level 1; # Lower level = less CPU for large files
gzip_min_length 10240; # Only compress files over 10 KB
# Compress dynamic responses on the fly; serve static with gzip_static
location /api/ {
proxy_pass http://backend;
gzip on;
gzip_comp_level 5;
}
location /static/ {
root /var/www;
gzip_static on; # use pre-compressed files
brotli_static on;
expires 1y;
}
}