<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/letting-cloudflare-serve-brotli-compressed-data-with-nginx-hvwgna845" -->

---
title: Letting Cloudflare serve Brotli-compressed data with nginx
description: Cloudflare won&#x27;t re-compress assets that your origin server already compressed — it simply passes them through. This means if nginx gzips a CSS file before it...
canonical: https://daily.dev/posts/letting-cloudflare-serve-brotli-compressed-data-with-nginx-hvwgna845
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Letting Cloudflare serve Brotli-compressed data with nginx | daily.dev
og:description: Cloudflare won&#x27;t re-compress assets that your origin server already compressed — it simply passes them through. This means if nginx gzips a CSS file before it...
og:url: https://daily.dev/posts/letting-cloudflare-serve-brotli-compressed-data-with-nginx-hvwgna845
og:image: https://api.daily.dev/og/posts/hVwGnA845.png
og:image:alt: Letting Cloudflare serve Brotli-compressed data with nginx
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Letting Cloudflare serve Brotli-compressed data with nginx

**[Mattias Geniar](https://daily.dev/sources/mattiasgeniar)** · 6 min read · 0 upvotes · 0 comments

## Summary

Cloudflare won't re-compress assets that your origin server already compressed — it simply passes them through. This means if nginx gzips a CSS file before it reaches Cloudflare, browsers get gzip even when they support Brotli. The fix is adding `gzip off;` in the nginx location block for Vite build assets (content-hashed, immutable files), so the origin sends them raw and Cloudflare can apply its own Brotli encoding. The result: 40 KB Brotli instead of 50 KB gzip for the same file. The post includes curl commands to diagnose the issue, verify the fix, and a Docker-based test to confirm nginx location-level `gzip off` overrides the global `gzip on`.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://ma.ttias.be/letting-cloudflare-serve-brotli-with-nginx>

## Questions this post answers

### Why is Cloudflare serving gzip instead of Brotli even though Brotli is enabled?

Cloudflare only applies its own Brotli compression when the origin sends assets uncompressed. If your origin (e.g., nginx) already sends a `content-encoding: gzip` response, Cloudflare passes it through unchanged rather than transcoding it to Brotli. The fix is to disable gzip at the origin for those assets so Cloudflare receives raw bytes and can compress them itself.

_Developers tuning CDN compression setups find edge cases like this covered on daily.dev._

### How do I disable nginx gzip for a specific location while keeping it on globally?

Add `gzip off;` inside the specific `location` block. This overrides the global `gzip on;` directive for just that path. For example, placing `gzip off;` in a `location ~* ^/build/assets/` block disables compression only for those files, while all other paths continue to use the global gzip setting. Tested on nginx 1.31.0 and 1.31.1.

_Engineers maintaining nginx configs track directive interactions like this on daily.dev._

### What is the actual file size difference between Brotli and gzip for CSS files served through Cloudflare?

For a real-world CSS bundle, Cloudflare's Brotli encoding produced approximately 40 KB versus 50 KB for gzip — roughly a 20% reduction. Cloudflare's edge Brotli level is not fixed and can vary between fetches (40–45 KB observed for the same file). Origin-side Brotli at quality 11 compresses harder but introduces maintenance risk tied to nginx version ABI compatibility.

_Teams optimizing asset delivery for PageSpeed scores follow compression trade-offs like these on daily.dev._

## Similar posts on daily.dev

- [Cloudflare Implements Cache Transcoding to Optimize Cache Storage with Zstandard](https://daily.dev/posts/cloudflare-implements-cache-transcoding-to-optimize-cache-storage-with-zstandard-yvmxvga81) · Arpit Bhayani · 0 upvotes · 0 comments
- [Cloudflare Tests Cache Transcoding to Reduce Storage Requirements](https://daily.dev/posts/cloudflare-tests-cache-transcoding-to-reduce-storage-requirements-iw5ae4p0h) · InfoQ · 0 upvotes · 0 comments
- [How we could save petabytes of cache storage with Zstandard and Pingora](https://daily.dev/posts/how-we-could-save-petabytes-of-cache-storage-with-zstandard-and-pingora-jfhpgwkm4) · Cloudflare · 3 upvotes · 0 comments
- [Is Minifying CSS Necessary? \(2023\)](https://daily.dev/posts/is-minifying-css-necessary-2023--rkdzefgf1) · Lobsters · 54 upvotes · 20 comments

---

Tags: [#webdev](https://daily.dev/tags/webdev), [#cloudflare](https://daily.dev/tags/cloudflare), [#nginx](https://daily.dev/tags/nginx), [#compression](https://daily.dev/tags/compression)

[View this post on daily.dev](https://daily.dev/posts/letting-cloudflare-serve-brotli-compressed-data-with-nginx-hvwgna845)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Letting Cloudflare serve Brotli-compressed data with nginx","url":"https://daily.dev/posts/letting-cloudflare-serve-brotli-compressed-data-with-nginx-hvwgna845","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/letting-cloudflare-serve-brotli-compressed-data-with-nginx-hvwgna845"},"datePublished":"2026-08-11T08:51:45.508Z","dateModified":"2026-08-11T08:53:41.293Z","description":"Cloudflare won't re-compress assets that your origin server already compressed — it simply passes them through. This means if nginx gzips a CSS file before it...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/7e4790c7ccdd45a351b761c11a54fc56?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/7e4790c7ccdd45a351b761c11a54fc56?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Mattias Geniar","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Mattias Geniar","logo":"https://media.daily.dev/image/upload/logos/placeholder.jpg","url":"https://daily.dev/sources/mattiasgeniar"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/letting-cloudflare-serve-brotli-compressed-data-with-nginx-hvwgna845","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"webdev,cloudflare,nginx,compression","timeRequired":"PT6M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Mattias Geniar","item":"https://daily.dev/sources/mattiasgeniar"},{"@type":"ListItem","position":3,"name":"Letting Cloudflare serve Brotli-compressed data with nginx"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/letting-cloudflare-serve-brotli-compressed-data-with-nginx-hvwgna845#faq","mainEntity":[{"@type":"Question","name":"Why is Cloudflare serving gzip instead of Brotli even though Brotli is enabled?","acceptedAnswer":{"@type":"Answer","text":"Cloudflare only applies its own Brotli compression when the origin sends assets uncompressed. If your origin (e.g., nginx) already sends a `content-encoding: gzip` response, Cloudflare passes it through unchanged rather than transcoding it to Brotli. The fix is to disable gzip at the origin for those assets so Cloudflare receives raw bytes and can compress them itself. Developers tuning CDN compression setups find edge cases like this covered on daily.dev."}},{"@type":"Question","name":"How do I disable nginx gzip for a specific location while keeping it on globally?","acceptedAnswer":{"@type":"Answer","text":"Add `gzip off;` inside the specific `location` block. This overrides the global `gzip on;` directive for just that path. For example, placing `gzip off;` in a `location ~* ^/build/assets/` block disables compression only for those files, while all other paths continue to use the global gzip setting. Tested on nginx 1.31.0 and 1.31.1. Engineers maintaining nginx configs track directive interactions like this on daily.dev."}},{"@type":"Question","name":"What is the actual file size difference between Brotli and gzip for CSS files served through Cloudflare?","acceptedAnswer":{"@type":"Answer","text":"For a real-world CSS bundle, Cloudflare's Brotli encoding produced approximately 40 KB versus 50 KB for gzip — roughly a 20% reduction. Cloudflare's edge Brotli level is not fixed and can vary between fetches (40–45 KB observed for the same file). Origin-side Brotli at quality 11 compresses harder but introduces maintenance risk tied to nginx version ABI compatibility. Teams optimizing asset delivery for PageSpeed scores follow compression trade-offs like these on daily.dev."}}]}
```

