Why Compression Matters in Modern Web Apps
When a browser requests HTML, CSS, JavaScript, or even image assets, the raw byte size can be a major factor in Time‑to‑First‑Byte (TTFB) and overall page load time. Enabling server‑side compression reduces the payload over the wire, often cutting transfer size by 60‑80 % for text‑based resources. Nginx ships with built‑in gzip
support, but the newer brotli
algorithm (Google’s open‑source compressor) delivers up to 30 % better compression ratios on UTF‑8 content.
TL;DR: Use Brotli for modern browsers, keep Gzip as a fallback for legacy clients.
1. Quick Compatibility Check
Browser | Gzip | Brotli |
---|---|---|
Chrome ≥ 49 | ✅ | ✅ |
Firefox ≥ 44 | ✅ | ✅ |
Safari ≥ 10.1 | ✅ | ✅ |
Edge ≤ 18 | ✅ | ❌ |
Internet Explorer | ✅ | ❌ |
If you support older versions of Edge or IE, you’ll still need Gzip. The rule of thumb is serve Brotli when Accept‑Encoding
includes br
, otherwise fall back to Gzip.
2. Installing the Brotli Module on Linux
Most modern distributions provide a pre‑compiled ngx_brotli
module. On Ubuntu 22.04 you can pull it from the official repository:
sudo apt-get update sudo apt-get install nginx-module-brotli # Verify the module is loaded nginx -V 2>&1 | grep -o brotli
If you compile Nginx from source, add the module during configuration:
cd /usr/local/src wget https://nginx.org/download/nginx-1.25.2.tar.gz tar xf nginx-1.25.2.tar.gz git clone https://github.com/google/ngx_brotli.git cd ngx_brotli && git submodule update --init cd ../nginx-1.25.2 ./configure \ --add-module=../ngx_brotli \ --with-http_ssl_module \ --with-http_v2_module make && sudo make install
After installation, reload Nginx:
sudo systemctl reload nginx
3. Core Configuration – Gzip
Place the following snippet in the http
block of your nginx.conf
(or an included file like /etc/nginx/conf.d/compression.conf
):
http { gzip on; gzip_comp_level 6; # 1‑9, 6 is a good balance gzip_min_length 256; # Do not compress tiny responses gzip_types text/plain text/css application/json application/javascript text/xml application/xml+rss; gzip_vary on; # Send Vary: Accept‑Encoding header gzip_proxied any; }
Key takeaways:
-
gzip_comp_level
: Higher levels increase CPU usage. For busy sites, 4‑6 is typical. -
gzip_vary
ensures caches store separate versions for compressed and uncompressed responses.
4. Core Configuration – Brotli
Add the Brotli block after the Gzip block. Nginx will automatically negotiate the best algorithm.
http { # ... gzip block above ... brotli on; brotli_comp_level 5; # 0‑11, 5‑7 gives best ratio without choking CPU brotli_types text/plain text/css application/json application/javascript text/xml application/xml+rss; brotli_static on; # Serve pre‑compressed .br files if they exist }
brotli_static
is a performance win: you can pre‑compress static assets during your CI pipeline and let Nginx serve them directly, bypassing runtime compression.
5. Conditional Enabling – Only for Text Assets
Compressing already‑compressed files (e.g., JPEG, PNG, MP4) wastes CPU cycles. The gzip_types
and brotli_types
directives already limit the scope, but you can also add a regex filter for extra safety:
location ~* \.(?:js|css|html|json|svg|txt)$ { # Inherit gzip/brotli from http block try_files $uri $uri/ =404; }
All other locations fall back to the default (no compression).
6. Testing Your Setup
6.1 Curl Checks
# Gzip only curl -H "Accept-Encoding: gzip" -I https://example.com/style.css # Brotli only curl -H "Accept-Encoding: br" -I https://example.com/style.css # Both – let server decide curl -H "Accept-Encoding: gzip, br" -I https://example.com/style.css
Look for the Content‑Encoding: gzip
or Content‑Encoding: br
header.
6.2 Lighthouse / WebPageTest
Run a Lighthouse audit (Chrome DevTools) or WebPageTest. Compare TTFB and Transfer Size before and after enabling Brotli. Expect a 10‑20 ms reduction in TTFB for typical HTML pages.
7. Monitoring CPU Impact
Compression adds CPU load. Use htop
or top
to watch the nginx
worker processes after a traffic spike. If you see sustained > 80 % CPU, consider:
- Lowering
brotli_comp_level
to 4. - Enabling
brotli_static
and pre‑compressing assets. - Offloading static content to a CDN that already handles Brotli.
You can also expose Nginx metrics to Prometheus via the ngx_http_stub_status_module
and visualize compression hit‑rates in Grafana.
8. When Not to Use Brotli
- Very low‑traffic sites where the added build‑step complexity outweighs the bandwidth savings.
- Legacy API endpoints serving binary payloads (e.g., protobuf) – compression is unnecessary and may break clients.
- Environments with strict CPU quotas (e.g., cheap shared VPS). Stick to Gzip at level 4.
9. Checklist for Production Rollout
- [ ] Install
ngx_brotli
(package or compile). - [ ] Add both Gzip and Brotli blocks to
nginx.conf
. - [ ] Restrict compression to text MIME types.
- [ ] Enable
brotli_static
and add a CI step to generate.br
files. - [ ] Test with
curl
and Lighthouse. - [ ] Monitor CPU and adjust
*_comp_level
as needed. - [ ] Document fallback behavior for browsers lacking Brotli support.
10. Final Thoughts
Balancing bandwidth savings against CPU overhead is a classic SRE trade‑off. By layering Gzip and Brotli intelligently, you get the best of both worlds: modern browsers enjoy the smallest possible payloads, while older clients still receive reliable compression. Keep an eye on your server’s load, and don’t forget to pre‑compress static assets to squeeze every last millisecond out of your response times.
For more hands‑on guides and real‑world case studies on web performance, check out https://lacidaweb.com.
Top comments (0)