DEV Community

Ramer Labs
Ramer Labs

Posted on

Performance Tuning for Nginx: When to Use Gzip vs Brotli Compression

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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

After installation, reload Nginx:

sudo systemctl reload nginx 
Enter fullscreen mode Exit fullscreen mode

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; } 
Enter fullscreen mode Exit fullscreen mode

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 } 
Enter fullscreen mode Exit fullscreen mode

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; } 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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)