Text compression: gzip, Brotli and Zstandard
Text compression shrinks HTML, CSS and JavaScript before they travel. How gzip, Brotli and Zstandard compare, how to check yours, and how to switch it on.
In this guide
What compression does
Text repeats itself. The same tags, class names, keywords and property names appear again and again. A compression method replaces the repeats with short references, and the result unpacks to exactly the original file. Nothing is lost.
The server and the browser agree on a method in a short exchange:
- The browser asks for a file and lists the methods it can unpack in the
Accept-Encodingrequest header. A current browser sends something likegzip, deflate, br, zstd. - The server picks one method, compresses the file with it, and names it in the
Content-Encodingresponse header. - The server adds
Vary: Accept-Encoding. That tells any cache in between to keep a separate copy for each method, so a packed file never reaches a client that cannot unpack it. - The browser unpacks the file and uses it.
How much does it save? MDN says some documents shrink by up to 70%. For the HTML page, Lighthouse assumes a saving of about two thirds. The exact figure depends on the file, and a file that is already small has little to gain.
It matters most for the files the browser needs before it can show anything. The HTML and the stylesheets in the head arrive sooner when they are smaller, which helps First Contentful Paint and Largest Contentful Paint. The gain is biggest on slow connections, where every kilobyte takes longer.
What to compress, and what to leave alone
The rule is simple: compress text, and do not compress what is already packed by its own format.
| File type | Compress? | Why |
|---|---|---|
| HTML, CSS, JavaScript, JSON, XML, plain text | Yes | Plain text with many repeats |
| SVG images and ICO icons | Yes | SVG is text; the Web Almanac counts both among the text files that benefit |
| TTF and OTF fonts | Yes | These older font formats are not compressed in themselves |
| WOFF2 fonts | No | Already compressed with Brotli (see web fonts) |
| JPEG, PNG, GIF, WebP, AVIF | No | The image format already compresses the data (see image formats) |
| MP4, WebM, MP3 and other audio and video | No | Packed by their codecs |
| ZIP and other archives | No | Packed already |
Very small files are not worth it either. Servers such as Nginx have a minimum size setting for this reason, and Lighthouse ignores an HTML page when it expects to save less than 1,400 bytes.
gzip, Brotli and Zstandard
Three methods matter today. Each has its own value in the two headers.
| gzip | Brotli | Zstandard | |
|---|---|---|---|
| Header value | gzip | br | zstd |
| Browser support | Every major browser | Chrome 50, Edge 15, Firefox 44, Safari 11 | Chrome 123, Edge 123, Firefox 126, Safari 26.3 |
| File size | The baseline | Smaller than gzip | Often smaller than Brotli at the same processor cost |
| Speed to compress | Faster than Brotli | Slower than gzip | Built for real-time compression |
| Best for | The fallback for everyone | Static files and cacheable pages | Sites behind a CDN that offers it |
Some notes on the table:
- gzip works everywhere. It is the safe fallback, and the one to keep switched on even when you add something newer.
- Brotli produces smaller files than gzip. MDN says it is slower to compress, so gzip may be the better choice for content that cannot be cached and has to be compressed on every visit. The 2025 Web Almanac puts Brotli's gain over gzip at 20% to 26%.
- Zstandard is the newest. MDN describes it as often better than Brotli at the same processor cost. Safari only supports it from version 26.3. A browser that cannot unpack it does not list it in
Accept-Encoding, so the server falls back to Brotli or gzip for that browser.
The newer methods are spreading, led by CDNs. In the 2025 Web Almanac, requests answered by a CDN were 46% Brotli, 42% gzip and 12% Zstandard on mobile. Requests answered by the site's own server were 39% Brotli and 61% gzip.
Check whether it is on
You cannot see compression in the page. You have to look at the headers.
- Open the page in Chrome, press Ctrl+Shift+J (Cmd+Option+J on a Mac), and open the Network tab. Reload the page.
- Click the request for the page or for a stylesheet or script.
- In the Headers tab, find
content-encodingunder Response Headers.br,gziporzstdmeans it is compressed. No such line means it is not. - To compare sizes, switch on Use large request rows in the Network settings. The Size column then shows two values: the top one is the compressed size on the network, the bottom one the size after unpacking.
The same check from a terminal asks for Brotli and gzip and prints only the two headers that matter:
curl -s -o /dev/null -D - -H 'Accept-Encoding: br, gzip' https://example.com/ | grep -i -E '^(content-encoding|vary)'Run it for the page, then for a CSS file and a JavaScript file. You want content-encoding on all three and vary: accept-encoding as well.
In the Lighthouse report that PageSpeed Insights shows, the Document request latency insight has a line that reads "Applies text compression" or "No compression applied". In Lighthouse 13.5 that check covers the HTML page only. Older versions listed every uncompressed text file under "Enable text compression". Use the Network panel for your CSS and JavaScript.
Turn it on
Look for the easy place first, because compression is often already on and you only need to check.
- Your host. Some hosts compress by default. If the check above shows it is off, ask the host to enable it, or look for a setting in the control panel.
- Your CDN. A CDN usually has a compression setting, and it often offers Brotli. web.dev describes two kinds of support: passing on files that your server already compressed, and compressing them itself. The Web Almanac observes that CDNs make this a simple configuration change instead of a change on every server.
- Your web server. If you run it yourself, enable the compression module and list the file types.
On WordPress, compression is normally a setting of the server or CDN, and some caching plugins have an option for it. Lighthouse's own advice for WordPress is to enable text compression in the web server configuration.
For Apache, the module mod_deflate does gzip, and mod_brotli does Brotli from version 2.4.26 on. A gzip setup for the common text types:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json image/svg+xml
</IfModule>For Nginx, gzip is built in but off until you switch it on. The type list adds to text/html, which is always compressed once gzip is on:
gzip on;
gzip_vary on; # adds Vary: Accept-Encoding
gzip_comp_level 5; # 1 to 9: higher is smaller but uses more processor time
gzip_min_length 256; # skip tiny responses
gzip_types text/css text/javascript application/javascript application/json image/svg+xml text/xml;Brotli on Nginx needs an extra module. Check what your host or distribution provides before you compile anything.
Two details trip people up. The type list is matched against the type the server really sends, so a script sent as application/javascript is not covered by a list that only says text/javascript; list both. And Nginx does not compress a request that came through a proxy, which it recognizes by the Via request header, unless gzip_proxied allows it. If a CDN or proxy sits in front of Nginx and the files arrive unpacked, check that setting.
Compress static files once
Compressing on every request costs processor time. For files that do not change, such as the CSS and JavaScript from a build, compress them once at the highest level and store the packed copies next to the originals. The Apache documentation describes the idea: mod_deflate compresses again for each request, so serving pre-compressed files avoids that work. Nginx can serve a stored .gz file with its gzip_static setting, although that module is not built by default. The Brotli module for Nginx has a matching setting for .br files.
Many build tools and CDNs do this for you. The result is the smallest files at no cost per visit. Keep the dynamic pages, which are built for each visitor, at a moderate level. web.dev suggests Brotli level 4 (or gzip level 6) for pages compressed on request, and the strongest levels, Brotli 11 (or gzip 9), for static files.
What can go wrong
- The type list is incomplete. JSON, SVG and fonts in older formats are the usual gaps.
- Compression is on for the page but not for the files. CSS and JavaScript sometimes come from a different host, such as a storage bucket, with its own settings.
- The cache serves the wrong copy. Without
Vary: Accept-Encoding, a shared cache can hand a packed file to a client that did not ask for it. The common server modules add the header for you. A custom setup may not. See caching explained. - A very high level on pages built per visit. The extra seconds of compression can slow the response. The time to first byte guide shows how to measure the wait.
- Nginx behind a proxy.
gzip_proxiedis off by default, so requests that arrive through a proxy get uncompressed answers.
Check your own page
Run the free audit and look at Document request latency. If it says "No compression applied", the HTML page is going out unpacked, and turning compression on is one of the quickest fixes on the list. Then check your CSS and JavaScript files in the Network panel, because the report does not list them. In the Web Almanac's 2025 data, more than a quarter of pages still failed Lighthouse's text compression test, so this is a common gap. For the server settings behind a slow first response, see choosing web hosting for speed.
Sources
- Compression in HTTP on MDN: how the browser and server negotiate, which files to skip, the server modules.
- Content-Encoding on MDN: the header values and the browser support table.
- Accept-Encoding on MDN: what browsers send.
- Enable text compression on Chrome for Developers: how to check a response in DevTools.
- CDN chapter, Web Almanac 2025 and page weight chapter: compression use across the web.
Start here
Free website audit
Live Google data for any public page: mobile and desktop.
Mobile + desktop · Lighthouse lab test · Real-user Chrome data when Google has it
Rather have this done for you? Speed optimization · Book a call