Brotli vs Gzip: Webserver-Komprimierung optimieren
Gzip und Brotli sind die zwei Komprimierungsalgorithmen, die heute relevant sind, wenn es um HTTP-Content-Encoding geht. Gzip ist seit Jahrzehnten dabei, Brotli ist neuer (2015, standardisiert in RFC 7932). Die übliche Darstellung ist "Brotli ist das neue, bessere Gzip" — das stimmt in einer speziellen Dimension, aber nicht pauschal. Die tatsächliche Antwort ist differenzierter.
Was beide machen
Beide komprimieren HTTP-Responses on-the-fly, bevor sie rausgeschickt werden. Der Browser sagt per Accept-Encoding-Header, was er versteht; der Server antwortet mit dem komprimierten Inhalt und einem Content-Encoding-Header.
Für den Client ist das transparent — der Browser dekomprimiert automatisch. Der Gewinn: textbasierte Inhalte (HTML, CSS, JS, JSON) schrumpfen typischerweise auf 20-30 % der Originalgröße.
Die relevanten Unterschiede
Kompressionsrate: Brotli komprimiert bei gleicher Arbeit besser als Gzip. Bei einer typischen React-Bundle-Datei sehe ich Brotli ~15-20 % kleiner als Gzip.
Dekompressions-Geschwindigkeit: Brotli ist beim Dekomprimieren langsamer als Gzip. Für den Browser ist das vernachlässigbar — der Unterschied liegt im einstelligen Millisekundenbereich, und die Zeit wird durch das kleinere Download-Volumen mehr als wettgemacht.
Kompressions-Geschwindigkeit: Hier wird's interessant. Brotli auf der höchsten Stufe (11) ist enorm langsam — unbrauchbar für On-the-fly-Komprimierung. Gzip auf Stufe 6 (Standard) ist schnell genug für jeden Request. Brotli auf Stufe 4-6 ist vergleichbar schnell wie Gzip auf Stufe 6.
Wofür welcher Algorithmus
Statische Assets (HTML, CSS, JS im Build) sollten mit Brotli-Level-11 vorkomprimiert werden. Das dauert einmal beim Build ein paar Sekunden und spart bei jedem Request Traffic. nginx kann die fertigen .br-Dateien direkt ausliefern, ohne live zu komprimieren.
Dynamischer Content (API-Responses, SSR-HTML) wird on-the-fly komprimiert. Dafür nimmst du Brotli Level 4-5 oder Gzip Level 6 — vergleichbarer CPU-Aufwand, Brotli komprimiert ~5-10 % besser.
Binärdaten (Bilder, Videos, bereits komprimierte Dateien) gar nicht. Beide Algorithmen vergrößern oft, was bereits komprimiert ist.
Die nginx-Konfiguration
Gzip ist Built-in, Brotli braucht das separate ngx_brotli-Modul:
apt install nginx libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static
Im http-Block:
gzip on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml application/xml+rss text/javascript;
gzip_vary on;
brotli on;
brotli_comp_level 5;
brotli_min_length 1024;
brotli_types text/plain text/css application/json application/javascript
text/xml application/xml application/xml+rss text/javascript;
brotli_static on;
brotli_static on ist der wichtige Trick: wenn eine Datei foo.js angefragt wird und foo.js.br daneben liegt, wird die fertig komprimierte Datei ausgeliefert. Sonst wird on-the-fly komprimiert.
Beide gleichzeitig konfigurieren — der Client wählt per Accept-Encoding. Moderne Browser nutzen Brotli, ältere fallen auf Gzip zurück.
Statische Vorkompression
Im Build-Prozess (Next.js, Webpack, Vite) fertige .br- und .gz-Dateien erzeugen:
find dist -type f \( -name "*.js" -o -name "*.css" -o -name "*.html" \) \
-exec brotli -q 11 -f {} \;
Das dauert beim Build ein paar Sekunden mehr, spart aber bei jedem Request CPU — und liefert bessere Kompression als live möglich.
Was man leicht falsch macht
gzip_min_length zu niedrig. Default ist 20 Bytes, aber unter 1 KB lohnt Komprimierung nicht — der Overhead frisst den Gewinn auf. Auf 1024 setzen.
MIME-Types nicht vollständig. Wer application/wasm oder image/svg+xml nicht in der Liste hat, lässt Komprimierung für diese Typen liegen.
Vary: Accept-Encoding vergessen. Ohne den Header cachen Proxies die komprimierte Version auch für Clients, die sie nicht verstehen. gzip_vary on setzt ihn.
Brotli war ursprünglich HTTPS-only gedacht. Der Standard erlaubte Brotli nur über HTTPS. Auf HTTP-Verbindungen fällt der Browser auf Gzip zurück. 2026 ist das kein Problem mehr, aber bei Legacy-Setups im Hinterkopf behalten.
Was das bringt
Auf meinem Portfolio (Next.js, ~150 KB an JS) sehe ich im Netzwerk-Tab:
- Unkomprimiert: ~150 KB
- Gzip Level 6: ~45 KB
- Brotli Level 11 (static): ~38 KB
Der Sprung von unkomprimiert zu gzip ist gewaltig. Der Sprung von gzip zu brotli-11 ist real, aber im einstelligen Prozent-Bereich auf das Total. Für einen mobilen Nutzer auf 4G: 7 KB weniger = ein paar hundert Millisekunden. Für Glasfaser: irrelevant.
Lohnt sich trotzdem — Brotli-Static einzurichten ist fünf Minuten Aufwand pro Projekt. Das macht man einmal, profitiert ewig.