Web Performance

What Are Gzip and Brotli Compression (and How to Enable Them)?

Gzip and Brotli shrink HTML, CSS and JavaScript before they are sent. What each is, how Brotli compares to Gzip, how to verify it, and how to enable it.

StackOptic Research Team17 May 202611 min read
Gzip and Brotli text compression for HTML, CSS and JavaScript

When a browser requests your HTML, CSS and JavaScript, those files are just text — and text compresses extremely well. Gzip and Brotli are the two standard ways to shrink that text before the server sends it, so the browser downloads a fraction of the original bytes and the page arrives faster. Enabling them is one of the cheapest, highest-leverage performance wins available: it is usually a single server or CDN setting, it needs no change to your code, and it can cut the size of text assets by 70% or more. In short: Brotli usually compresses smaller than Gzip and is now supported almost everywhere, Gzip is the universal fallback, you verify either one with the Content-Encoding response header, and you should never apply them to already-compressed images, video or fonts. This guide explains what each one is, how they compare, how to check whether yours is working, and how to turn them on.

It is one of the quieter levers in how to make your website load faster.

What text compression actually does

Compression works by finding repetition and redundancy in data and encoding it more efficiently. Text — and web code is text — is full of repetition: the same HTML tags, the same CSS property names, the same JavaScript keywords and variable names appear over and over. A compression algorithm spots those repeated patterns and replaces them with short references, so a file that contained the word function two hundred times no longer has to spell it out two hundred times. When the browser receives the compressed file, it reverses the process and reconstructs the original byte-for-byte. This is lossless compression: nothing is thrown away, unlike the lossy compression used for photographs where some detail is discarded to save space.

The payoff is bandwidth. A 300 KB JavaScript bundle might travel as 90 KB or less once compressed, which means roughly a third of the download time and a third of the data cost for the user. Because the browser advertises which compression methods it understands and the server picks one, the whole exchange is automatic and invisible once configured. The mechanism is built into HTTP itself, so it works with any server, any framework and any CDN.

How the negotiation works

Compression is negotiated through two HTTP headers, and understanding them makes everything else clearer. When the browser makes a request, it sends an Accept-Encoding header listing the compression methods it supports, typically something like Accept-Encoding: gzip, deflate, br — where br is Brotli. The server looks at that list, decides which method to use (usually the most effective one both sides support), compresses the response, and sends back a Content-Encoding header naming the method it actually used. The browser sees Content-Encoding: br or Content-Encoding: gzip, decompresses accordingly, and renders the page.

This negotiation is why compression degrades gracefully. If a client somehow does not advertise Brotli, the server simply falls back to Gzip; if it supports neither, the server sends the file uncompressed and the page still works, just larger. You never have to choose one method exclusively — a well-configured server offers Brotli to clients that want it and Gzip to everyone else.

Gzip: the universal standard

Gzip has been the workhorse of web compression for decades. It is based on the DEFLATE algorithm and is supported by every browser, every server and every proxy in existence — there is no client on the modern web that cannot handle Gzip. That universality made it the default choice for years, and it remains the reliable baseline. Gzip offers compression levels from 1 (fastest, least compression) to 9 (slowest, most compression), letting you trade CPU time against output size. For static files that are compressed once and cached, a high level makes sense because the cost is paid only once; for content compressed on the fly per request, a middle level balances speed and size.

Gzip's strength is its ubiquity and speed; its limitation is that newer algorithms can do better on the kind of repetitive text that web assets contain. That is where Brotli comes in.

Brotli: smaller, and now everywhere

Brotli is a newer compression algorithm, developed by Google and released around 2015, designed specifically with web content in mind. Its headline advantage is that it usually produces smaller files than Gzip for HTML, CSS and JavaScript at comparable settings. One reason is a clever design choice: Brotli ships with a built-in static dictionary of common words, phrases and substrings that appear frequently across the web — common HTML tags, CSS keywords, JavaScript tokens and so on. Because both the compressor and the browser already know this dictionary, Brotli can reference those common patterns without having to include them in the file at all, squeezing out extra bytes that Gzip cannot.

Brotli also offers a wide range of quality levels, from 0 to 11. The highest levels compress the most but are slow, which makes Brotli best suited to static assets compressed ahead of time and cached — your CSS and JavaScript bundles, for example, compressed once at build or first request and then served many times. For dynamic responses generated per request, a lower Brotli level (or Gzip) avoids spending too much CPU on each hit. Crucially, browser support for Brotli is now effectively universal across modern browsers, so for the vast majority of visitors Brotli is available and there is no downside to offering it with Gzip as the fallback.

Gzip vs Brotli at a glance

AspectGzipBrotli
ReleasedLong-established (DEFLATE-based)Newer, by Google (~2015)
Typical text compressionGoodUsually smaller than Gzip
Built-in web dictionaryNoYes — common web strings
Compression levels1 to 90 to 11
Browser supportUniversalEffectively universal (modern browsers)
Best roleReliable fallback; fast at lower levelsPrimary choice for static text assets
High-level compression speedFasterSlower at top levels (compress once, cache)

The practical strategy that follows from this table is simple: serve Brotli to clients that support it and Gzip to those that do not, compress static assets at a high level once and cache the result, and use a more moderate level for anything compressed dynamically. Most modern servers and CDNs make exactly this arrangement easy, and many CDNs do it for you by default.

What to compress — and what not to

This is the part teams most often get wrong, so it is worth being precise. Compression helps text-based files enormously and helps already-compressed binary files not at all. Re-running Gzip or Brotli over a JPEG does not make it meaningfully smaller — the image format already compressed it — and you simply burn CPU for no benefit, occasionally even producing a slightly larger file.

Compress these (text-based):

  • HTML documents
  • CSS stylesheets
  • JavaScript files
  • JSON and XML (including API responses and RSS feeds)
  • SVG images (SVG is text/markup, so it compresses well)
  • Plain text, and web fonts in the older formats

Do not compress these (already compressed):

  • JPEG, PNG, WebP, AVIF and GIF images
  • MP4, WebM and other video; MP3 and other audio
  • woff2 fonts (the format is already compressed internally)
  • ZIP, gzip and other archive files

Server and CDN configurations let you specify exactly which MIME types to compress, so the correct setup is to list the text types and leave everything else alone. Note the SVG nuance in particular: because SVG is XML text, it benefits from compression like any other text asset, which ties into the image-format advice in how to optimize images for the web.

How to verify compression is working

Never assume compression is on — configurations get missed, and a surprising number of sites ship uncompressed text without anyone noticing. Checking takes seconds:

  1. Chrome DevTools Network panel. Open DevTools, go to Network, reload the page, and click on a text resource — the HTML document, a .css file or a .js file. In the Headers tab, look under Response Headers for Content-Encoding. A value of br means Brotli is active, gzip means Gzip, and the absence of the header on a text file means it is being sent uncompressed. You can also add the Content-Encoding column to the Network table to see it for every request at once, and compare the transferred size against the actual (uncompressed) size — a large gap confirms compression is working.
  2. curl from the command line. Run curl -I -H "Accept-Encoding: br, gzip" https://example.com and read the Content-Encoding line in the response headers. This explicitly tells the server you accept both methods and shows which it returns.
  3. Online header tools and audits. Header-inspection sites, and broader audits including PageSpeed Insights (which flags "Enable text compression" when it is missing), will report whether text assets are compressed.

Reading response headers is a useful general skill — the same technique reveals caching, security and CDN configuration too, as covered in how to read a website's HTTP headers.

How to enable it on Nginx

On Nginx, Gzip is built in and enabled through the gzip directives, while Brotli requires the ngx_brotli module (included in many distributions and in the official Nginx Docker images). A typical configuration enables both, lists the MIME types to compress, and sets a minimum file size so tiny files are not compressed (the overhead is not worth it below a few hundred bytes):

  • Turn on gzip on; and set gzip_types to your text MIME types.
  • Add brotli on; and brotli_types with the same list, and set brotli_static on; to serve pre-compressed .br files where they exist.
  • Set a sensible gzip_min_length / minimum so trivially small responses are skipped.

Serving pre-compressed static files — compressing your CSS and JS to .br and .gz at build time and letting Nginx serve them directly — gives you Brotli's highest compression without paying the CPU cost on every request, which is the ideal setup for static assets.

How to enable it on Apache

On Apache, Gzip is provided by mod_deflate and Brotli by mod_brotli. You enable the modules and then, typically in the server config or an .htaccess file, specify which MIME types to compress:

  • Enable mod_deflate and add the text MIME types via AddOutputFilterByType DEFLATE for HTML, CSS, JS, JSON, XML and SVG.
  • Enable mod_brotli and add AddOutputFilterByType BROTLI_COMPRESS for the same types.
  • Apache negotiates automatically, preferring Brotli for clients that advertise it and falling back to Gzip otherwise.

As with Nginx, restrict the filters to text types and leave images, video and woff2 fonts untouched.

How to enable it on a CDN

If you serve your site through a CDN — which, as what is a CDN, and do you need one explains, most growing sites should — compression is usually the easiest of all. Major CDNs handle it as a setting at the edge, so you do not have to touch your origin server's configuration at all:

  • Cloudflare applies Gzip and Brotli automatically for eligible content types, with Brotli available as a toggle and often on by default.
  • Fastly, Amazon CloudFront and others expose compression as a configuration option, compressing text responses at the edge.
  • Because the CDN compresses once and caches the result, it can use strong compression efficiently and serve the compressed copy to every subsequent visitor in the region.

The practical advice: if you are behind a CDN, check whether Brotli is already enabled (it frequently is) and confirm it with the Content-Encoding header before configuring anything at the origin. There is little point compressing at both layers.

A worked example

Suppose PageSpeed Insights flags "Enable text compression" on your site, estimating savings of several hundred kilobytes. You open the Network panel and confirm: the main HTML document and three large JavaScript bundles have no Content-Encoding header — they are being sent raw. You enable Brotli (with Gzip fallback) on your server, listing HTML, CSS, JS, JSON and SVG as the compressed types, and pre-compress the static bundles at a high Brotli level. After deploying, you reload and check the headers again: the document and bundles now show Content-Encoding: br, and the transferred sizes have dropped by roughly two-thirds. The "Enable text compression" warning disappears, TTFB-adjacent download time shrinks, and the change took one configuration edit and no code. This is the typical shape of compression work — a one-time setup that quietly benefits every page load thereafter.

Compression and the bigger picture

Compression is a delivery optimisation: it reduces the bytes on the wire for the assets you have already decided to ship. That makes it complementary to, not a substitute for, the work of shipping fewer and smaller assets in the first place. Compressing a bloated 2 MB JavaScript bundle to 600 KB is a real win, but shipping less JavaScript so the bundle was never 2 MB is a bigger one — the two stack. The same is true for CSS: compress it, but also remove what is unused, as how to optimize CSS for faster pages covers. Think of compression as the last step that makes whatever you send as small as it can be, layered on top of the page-weight discipline in how to reduce JavaScript and speed up your site.

There is a sustainability angle too. Fewer bytes transferred means less energy spent moving data across the network, so compression modestly reduces a page's carbon footprint at the same time as speeding it up — another case of the performance win and the efficiency win arriving together.

Common mistakes

  • Assuming compression is on without checking the Content-Encoding header — many sites ship uncompressed text unknowingly.
  • Compressing already-compressed files (images, video, woff2), wasting CPU for no benefit.
  • Forgetting Brotli and serving only Gzip, leaving easy byte savings on the table.
  • Compressing dynamic responses at the maximum level, spending excessive CPU per request instead of using a moderate level or pre-compressing static files.
  • Compressing at both origin and CDN redundantly, instead of letting the edge handle it once.

Go deeper

Want to see whether your text assets are compressed, alongside performance, SEO and security? Analyse any URL with StackOptic — free, no sign-up.

Frequently asked questions

What is the difference between Gzip and Brotli?

Both are lossless compression algorithms that shrink text-based files before transfer, but Brotli is newer and usually achieves smaller files than Gzip at comparable settings, especially for HTML, CSS and JavaScript. Brotli, developed by Google, ships with a built-in dictionary of common web strings that helps it compress web content well. Gzip is older and universally supported, so it remains the safe fallback for the rare client that does not advertise Brotli support.

Is Brotli better than Gzip?

For serving static text assets, Brotli generally produces smaller files than Gzip at equivalent or higher compression levels, which means fewer bytes over the wire and faster downloads. Browser support for Brotli is now effectively universal. Gzip still has a role as a fallback and for cases where Brotli is unavailable, and at its highest levels Brotli can be slower to compress, so it is best applied to static files that are compressed once and cached, not regenerated per request at maximum effort.

How do I know if my website uses compression?

Open Chrome DevTools, go to the Network panel, reload the page, click a text resource such as the HTML document or a CSS file, and look at the Response Headers for Content-Encoding. A value of br means Brotli, gzip means Gzip, and no Content-Encoding header on a text file means the response is uncompressed. You can also run curl -I -H 'Accept-Encoding: br,gzip' against a URL, or use any online header-inspection tool.

How do I enable Gzip or Brotli compression?

It is a server or CDN configuration. On Nginx you enable the gzip directives and add the Brotli module with brotli on and a list of MIME types; on Apache you use mod_deflate for Gzip and mod_brotli for Brotli. On a CDN such as Cloudflare or Fastly it is usually a single setting, and Brotli is frequently on by default. After enabling it, always verify with the Content-Encoding header that compressed responses are actually being served.

Which files should not be compressed?

Files that are already compressed gain little or nothing from Gzip or Brotli and only waste CPU re-processing them. That includes most images (JPEG, PNG, WebP, AVIF, GIF), video and audio (MP4, WebM, MP3), and modern font formats (woff2 is already compressed). Restrict text compression to text-based types: HTML, CSS, JavaScript, JSON, XML, SVG and plain text. Most server and CDN configurations let you specify exactly which MIME types to compress.

Analyse any website with StackOptic

Get the full technology stack, performance, security and SEO report in seconds — free.

Analyse a website

Related articles