Brotli vs Gzip: Webserver-Komprimierung optimieren

Comparison of Brotli and Gzip compression algorithms for web servers, with Nginx configuration best practices and performance optimization strategies.

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.