Nginx brotli compression (developed by Google) which helps reducing ~18% latency over gzip

Aug 12, 2018 · 5 min read

Fast page load leads to best customer experience and the most efficient strategy one can think in order to increase the engagement/business. This post is all about giving the website visitors something to experience as fast as possible i.e fast page load. It helps in SEO as well, Google has indicated page speed is one of the signals used by its algorithm to rank pages.

Image for post
Image for post
photo credit

What is Brotli?

Just like gzip, brotli is also a compression algorithm. It is developed by Google and serves best for text-based static resources (js,css,html,json) compression. The reason being, it uses a dictionary of common keywords and phrases on both client and server side and thus gives a better compression ratio.

Identify browser support

Browsers which supports brotli send ‘br’ along with ‘gzip’ in accept-encoding request header. If brotli is enabled on your web server, you will get response in brotli compressed format.

Image for post
Image for post
check content-encoding value in response header

Brotli in action

I tried brotli compression for javascript and css:

  • Javascript files compressed with brotli are ~17% smaller than gzip (gzip file fize: 326KB vs brotli file fize: 271KB)
  • CSS files are 20% smaller than gzip (gzip file fize: 61.1KB vs brotli file fize: 48.5KB)
  • According to certsimple, for HTML content, it’s 21% smaller than gzip (I have not tried yet)

Brotli or gzip should not be used for binary files like JPEG, PNG, MP4. They are already compressed with format-specific compression

We will use docker to try this and check file size with brotli compression. (follow this article to install docker and understand basic commands of docker). You can do a simple google where can find many articles which will help you build nginx with ngx_brotli module. I have used pre installed nginx brotli docker image for this demo:

mkdir ~/nginx_brotli_demo
cd ~/nginx_brotli_demo/
mkdir html_static_files

create a landing page which will include sample js & css

nano ~/nginx_brotli_demo/html_static_files/index.html

copy this content in index.html

Now create mycss1.css & myjs1.js files and add content in those files

nano ~/nginx_brotli_demo/html_static_files/mycss1.css
nano ~/nginx_brotli_demo/html_static_files/myjs1.js

Create nginx.conf for gzip

mkdir nginx_gzip_conf
nano ~/nginx_brotli_demo/nginx_gzip_conf/nginx.conf

nginx.conf with only gzip on;

create 1 more nginx.conf for brotli

mkdir nginx_brotli_conf
nano ~/nginx_brotli_demo/nginx_brotli_conf/nginx.conf

nginx.conf with brotli & gzip both on;

Now create a docker compose file which will have configuration to start 2 containers, 1 with container name ‘nginx-gzip’ (running on port 8080) which will have only gzip nginx config mounted and other container name ‘nginx-brotli’ (running on port 8081) will have brotli nginx config.

nano docker-compose.ymldocker-compose up -d # start containers
Image for post
Image for post
docker-compose up -d output
docker ps -a # check containers are running or not
Image for post
Image for post
STATUS should be UP

Now open chrome browser (version 63+) or any brotli supported browser and check size of file and Conte

Image for post
Image for post
http://localhost:8080 (Content-Encoding: gzip) js file size: 326KB
Image for post
Image for post
http://localhost:8081 (Content-Encoding: brotli) js file size: 271KB

You can open http://localhost:8081 on any browser which does not support brotli, Nginx will automatically fallback it to gzip

Is Brotli slower than gzip?

You may have read that Brotli is ‘slower than gzip’, so you can’t use it for dynamic content. This comment is not true, since anyone who uses the brotli for comparison they go with default options.

time brotli — input myjs1.js — output
time gzip myjs1.js

The default option of brotli command take compression level to 11, which is maximum and hence it takes time to generate compressed file but size will be way smaller than gzip. On the other size the default option of gzip commands takes compression level as 6, which is balanced between time it takes to generate compressed file and file size. One should compare with following to compare exact time taken by each compression algorithm:

time brotli -5 — input myjs1.js — output
time gzip myjs1.js

Brotli on production with Nginx

For static assets, we’ll compress the hell out of them with pre-compressed .br files using 11 — since we can serve these immediately for every request. Make a script to go into your app’s ‘public’ directory, finding files ending in ‘css’, ‘js’, ‘json’ or ‘svg’, and using the ‘brotli’ command to create files with the same name, using 11 compression, and a .br extension. The ‘force’ isn’t as scary as it sounds: it just overwrites existing files.

run this shell script at the time of frontend deployment

For dynamic content, we should use compression level 4 or 5, which still produces smaller responses but takes less time to compress than gzip or brotli on a higher setting. This way browsers only have to wait a short time for us to compress the responses. Add following in html block of nginx.conf

brotli on;
brotli_comp_level 4;
brotli_types text/plain text/css application/javascript application/json image/svg+xml application/xml+rss;
brotli_static on;

What CDN provider says about brotli

Apache HTTP Server + Brotli

brotli compression is also supported on Apache HTTP Server version 2.4.26 and later

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store