Kompression im Vergleich: Brotli vs. Gzip
60fps
ms
Performance · Netzwerk · Kompression · Brotli
Kompression im Vergleich: Brotli vs. Gzip
DEFLATE, Wörterbücher und die richtige Konfiguration

Jedes unkomprimierte HTML-, CSS- oder JS-Byte kostet Übertragungszeit, besonders auf mobilen Verbindungen mit hoher Latenz. Gzip ist der verlässliche Standard, aber Brotli komprimiert Web-Text durch ein eingebautes Wörterbuch häufiger Begriffe spürbar kleiner. Dieser Artikel zeigt, wie beide Verfahren technisch funktionieren, wo die Kompressionsraten tatsächlich liegen und wie man sie in Nginx und Varnish für Magento richtig konfiguriert.

14 Min. Lesezeit DEFLATE · LZ77 · Huffman · Wörterbuch Nginx · Varnish · Magento 2

1. Warum Textkompression bei HTML, CSS und JS zählt

HTML, CSS, JavaScript und SVG sind reiner Text und damit hochredundant: sich wiederholende Tag-Namen, verschachtelte Klassenlisten, ähnliche CSS-Deklarationen und wiederkehrende Funktionsnamen erzeugen enorm viel Redundanz im Byte-Strom. Ein typisches Tailwind-CSS-Bundle mit tausenden Utility-Klassen oder ein Hyvä-JS-Bundle mit wiederholten Alpine.js-Direktiven ist im Rohzustand oft mehrere hundert Kilobyte groß, obwohl die tatsächliche Informationsdichte viel geringer ist. Ohne Textkompression überträgt der Server genau diese Redundanz Byte für Byte über das Netzwerk, statt sie zu eliminieren.

Der Effekt ist auf mobilen Verbindungen mit hoher Latenz und begrenzter Bandbreite am stärksten spürbar, aber auch im Glasfasernetz zählt jedes eingesparte Kilobyte, weil TCP-Slow-Start die effektive Bandbreite in den ersten Round-Trips ohnehin begrenzt. Ein unkomprimiertes HTML-Dokument von 150 KB kann mehrere zusätzliche TCP-Segmente und damit messbare Millisekunden an Übertragungszeit kosten, bevor der Browser überhaupt mit dem Rendering beginnen kann. Kompression wirkt hier nicht auf die Serverantwortzeit, sondern gezielt auf die Downloadphase, die direkt in Largest Contentful Paint und Time to Interactive einfließt.

2. Gzip und DEFLATE: LZ77 und Huffman-Codierung

Gzip ist ein Container-Format um den DEFLATE-Algorithmus, der aus zwei kombinierten Techniken besteht. Zuerst durchsucht LZ77 die Eingabe mit einem gleitenden Fenster von 32 KB nach bereits gesehenen Byte-Sequenzen. Findet der Encoder eine Wiederholung, ersetzt er sie durch ein kompaktes Distanz-Länge-Paar, das auf die frühere Fundstelle zurückverweist, statt die Bytes erneut zu übertragen. Bei stark repetitivem Text wie CSS-Selektoren oder wiederkehrenden HTML-Attributen greift dieser Schritt sehr häufig und reduziert die Datenmenge bereits deutlich, bevor überhaupt die zweite Stufe beginnt.

Im zweiten Schritt wendet DEFLATE Huffman-Codierung auf das Ergebnis von LZ77 an: häufig vorkommende Bytes und Backreferences bekommen kürzere Bitmuster zugewiesen, seltene bekommen längere. Das ist reine Entropiecodierung ohne Kontextwissen über den Inhalt. Die entscheidende Einschränkung von Gzip liegt im 32-KB-Fenster von LZ77: Wiederholungen, die weiter als 32 KB auseinanderliegen, etwa ähnliche Blöcke am Anfang und Ende einer langen JS-Datei, kann der Algorithmus schlicht nicht mehr referenzieren und muss sie erneut vollständig codieren.

3. Brotli: größeres Fenster und eingebautes Wörterbuch

Brotli setzt an genau dieser Schwachstelle an: Das Sliding Window kann bis zu 16 MB groß sein, also 512-mal größer als bei Gzip. Dadurch findet der Encoder auch Wiederholungen über sehr lange Dateien hinweg, was bei großen, gebündelten JS-Vendor-Chunks oder umfangreichen CSS-Dateien einen echten Unterschied macht. Zusätzlich nutzt Brotli eine feinere Kontextmodellierung bei der Entropiecodierung als reines Huffman, wodurch die Bitzuteilung enger an die tatsächliche lokale Wahrscheinlichkeitsverteilung der Daten angepasst wird.

Der eigentliche Clou für Web-Inhalte ist aber Brotlis statisches Wörterbuch: eingebettet sind rund 13.000 Strings und Phrasen, die aus einem großen Korpus realer Web-Inhalte extrahiert wurden - HTML-Tags wie <div class=", CSS-Eigenschaften wie background-color oder display: flex, und häufige JS-Schlüsselwörter wie function oder document.getElementById. Weil dieses Wörterbuch schon vor der Kompression bekannt ist, kann Brotli auch in kleinen, kurzen Dateien ohne viel interne Wiederholung stark komprimieren, indem es Treffer im Wörterbuch statt im Dateiinhalt selbst referenziert. Gzip hat keine vergleichbare Vorwissen-Komponente und muss jede Redundanz aus der Datei selbst herleiten.

4. Kompressionsraten in der Praxis

In Benchmarks mit realen Web-Assets liegt Brotli typischerweise 15 bis 25 % kleiner als Gzip bei vergleichbarer Kompressionsstufe, wenn beide auf HTML, CSS oder JavaScript angewendet werden. Ein 200 KB großes CSS-Bundle, das mit Gzip -9 auf rund 35 KB schrumpft, landet mit Brotli -q 11 häufig bei 26 bis 29 KB. Bei generiertem, hochrepetitivem CSS wie Tailwind-Utility-Klassen fallen die Unterschiede oft größer aus, weil sowohl das große Sliding Window als auch das Wörterbuch greifen; bei individuellem Anwendungscode mit weniger Redundanz sind die Unterschiede kleiner.

Diese Zahlen sind Richtwerte, keine Garantie. Der tatsächliche Gewinn hängt stark vom konkreten Inhalt ab: stark komprimierte oder bereits binäre Formate wie JPEG oder WOFF2 profitieren kaum von zusätzlicher Textkompression, während generischer Boilerplate-Code besonders stark schrumpft. Wer die Wirkung belastbar einschätzen will, sollte reale Assets aus dem eigenen Build mit beiden Verfahren komprimieren und die tatsächliche Dateigröße vergleichen, statt sich auf pauschale Prozentwerte zu verlassen.

5. CPU-Kosten: Qualitätsstufen richtig wählen

Beide Verfahren bieten einstellbare Kompressionsstufen, die einen direkten Zielkonflikt zwischen Kompressionsrate und Rechenzeit abbilden. Gzip kennt die Stufen 1 bis 9, wobei Stufe 6 den in der Praxis meistgenutzten Kompromiss darstellt. Brotli kennt die Qualitätsstufen 0 bis 11, und genau hier liegt der entscheidende Unterschied: Brotli-Qualität 11 liefert die beste Kompression, ist aber gegenüber niedrigeren Stufen um ein Vielfaches teurer in der Rechenzeit - bei großen Dateien teils zehn- bis hundertmal langsamer als Gzip -9, für einen zusätzlichen Gewinn von oft nur wenigen Prozentpunkten gegenüber Brotli-Qualität 9 oder 10.

Diese Kostenkurve entscheidet direkt über den sinnvollen Einsatzort: Qualität 11 gehört ausschließlich in den Build-Prozess, wo Rechenzeit reichlich vorhanden ist und nur einmal pro Deployment anfällt. Für dynamische, zur Laufzeit komprimierte Antworten muss eine deutlich günstigere Stufe gewählt werden, etwa Gzip-Level 4 bis 6 oder Brotli-Qualität 4 bis 5, weil sonst jeder einzelne PHP-FPM- oder Nginx-Worker-Prozess durch die Kompression selbst zum Flaschenhals wird.


# Compare wall-clock time and output size across compression levels
# on a realistic 180 KB JS bundle

time gzip -9 -c app.bundle.js > app.bundle.js.gz
# real  0m0.041s   size: 47 KB

time brotli -q 5 -c app.bundle.js > app.bundle.js.br.q5
# real  0m0.038s   size: 44 KB

time brotli -q 11 -c app.bundle.js > app.bundle.js.br.q11
# real  0m2.914s   size: 36 KB

# Quality 11 is ~75x slower than quality 5 for roughly 18% extra savings.
# Fine for a one-time build step, unacceptable per HTTP request.

6. Content Negotiation: Accept-Encoding und Content-Encoding

Welches Kompressionsverfahren tatsächlich zum Einsatz kommt, handeln Browser und Server bei jeder Anfrage über Content Negotiation aus. Der Client sendet den Request-Header Accept-Encoding mit einer Liste der unterstützten Verfahren, optional gewichtet mit q-Werten, zum Beispiel Accept-Encoding: br, gzip, deflate. Der Server wählt daraus das beste Verfahren, das er selbst unterstützt, komprimiert die Antwort entsprechend und kennzeichnet das Ergebnis mit dem Response-Header Content-Encoding, damit der Browser weiß, wie er die Antwort vor der Verarbeitung dekomprimieren muss.

Ein häufig übersehenes Detail: Der Server muss zusätzlich Vary: Accept-Encoding setzen, sobald eine Antwort komprimiert ausgeliefert werden kann. Ohne diesen Header können vorgelagerte Caches - ein CDN, ein Reverse Proxy oder sogar der Browser-eigene Cache - eine für einen Brotli-fähigen Client komprimierte Antwort versehentlich an einen Client ohne Brotli-Unterstützung ausliefern, was zu unlesbarem, binärem Text auf der Seite führt. Vary: Accept-Encoding sorgt dafür, dass der Cache pro Encoding-Variante einen eigenen Eintrag führt.


# Client negotiates compression via Accept-Encoding
curl -s -D - -H "Accept-Encoding: br, gzip" \
  https://shop.example.com/static/frontend/Mironsoft/default/de_DE/css/styles.css \
  -o /dev/null

# Relevant response headers:
# HTTP/2 200
# content-encoding: br
# vary: Accept-Encoding
# content-length: 28114

# Without Brotli support, the same request falls back to gzip:
curl -s -D - -H "Accept-Encoding: gzip" \
  https://shop.example.com/static/frontend/Mironsoft/default/de_DE/css/styles.css \
  -o /dev/null
# content-encoding: gzip
# content-length: 35892

7. Pre-Compression beim Build vs. On-the-fly bei Magento

Für statische, unveränderliche Assets ist Pre-Compression die richtige Strategie: Während des Build-Schritts werden neben jeder Originaldatei bereits fertig komprimierte .br- und .gz-Varianten erzeugt, meist über ein Webpack- oder Vite-Plugin oder ein eigenes Build-Skript. Der Webserver muss zur Laufzeit dann nur noch die passende Variante anhand des Accept-Encoding-Headers ausliefern, ohne selbst zu komprimieren. Das verschiebt die teure Brotli-Qualität-11-Berechnung vollständig aus dem Request-Pfad heraus in einen Zeitpunkt, an dem CPU-Zeit praktisch beliebig zur Verfügung steht.

Für dynamisch generiertes HTML, das sich je nach Nutzer, Warenkorb-Inhalt oder A/B-Test unterscheidet, funktioniert Pre-Compression nicht, weil der Inhalt zum Build-Zeitpunkt noch gar nicht existiert. Hier bleibt nur On-the-fly-Kompression zur Laufzeit, allerdings mit einer deutlich günstigeren Qualitätsstufe als beim Build. Diese Abwägung zwischen Pre-Compression für Statik und On-the-fly-Kompression für Dynamik ist der zentrale Entwurfsentscheid für jede Kompressionsstrategie.


// vite.config.js - precompress build output to .br and .gz
// alongside every static asset, at maximum quality since
// this only runs once per deployment, not per request
import { defineConfig } from 'vite';
import viteCompression from 'vite-plugin-compression';

export default defineConfig({
  plugins: [
    viteCompression({
      algorithm: 'brotliCompress',
      ext: '.br',
      threshold: 1024,       // skip tiny files, overhead outweighs gain
      compressionOptions: { level: 11 },
      deleteOriginFile: false,
    }),
    viteCompression({
      algorithm: 'gzip',
      ext: '.gz',
      threshold: 1024,
      compressionOptions: { level: 9 },
      deleteOriginFile: false,
    }),
  ],
});

8. Nginx und Varnish für Magento konfigurieren

In Nginx übernimmt das Modul ngx_brotli die Brotli-Unterstützung, das standardmäßig nicht mitkompiliert ist und entweder als dynamisches Modul oder über einen eigenen Build eingebunden werden muss. Die Direktive brotli_static on weist Nginx an, zuerst nach einer vorab erzeugten .br-Datei neben dem angefragten Asset zu suchen und diese direkt auszuliefern, ohne selbst zu komprimieren - genau das Pre-Compression-Ergebnis aus dem Build-Schritt. gzip_static on funktioniert analog als Fallback für Clients ohne Brotli-Unterstützung. Für Fälle, in denen keine vorkomprimierte Datei existiert, definiert brotli_comp_level beziehungsweise gzip_comp_level die Stufe für die On-the-fly-Kompression - hier bewusst niedrig halten, siehe Abschnitt 5.

Varnish war historisch ein Problemfall für Kompression: Die Standardkonfiguration vieler VCL-Vorlagen normalisiert den Accept-Encoding-Header auf nur eine Variante, meist gzip, um die Anzahl der Cache-Varianten pro URL klein zu halten - Varnish selbst unterstützt kein natives Brotli. In einem Magento-Stack übernimmt deshalb meist Nginx vor oder hinter Varnish die Brotli-Aushandlung, während Varnish nur die gzip-komprimierte oder unkomprimierte Variante cached. Wichtig ist, den Accept-Encoding-Header vor dem Cache-Lookup zu normalisieren, damit nicht für jede denkbare Kombination aus Client-Encodings eine eigene Cache-Variante entsteht.


# nginx.conf - serve precompressed assets, fall back to on-the-fly
# at a deliberately cheap level for cache-miss/dynamic responses

brotli on;
brotli_static on;              # serve prebuilt .br files directly
brotli_comp_level 5;           # cheap fallback level, not 11
brotli_types text/html text/css application/javascript
             application/json image/svg+xml;

gzip on;
gzip_static on;                # serve prebuilt .gz files directly
gzip_comp_level 5;              # cheap fallback level, not 9
gzip_types text/html text/css application/javascript
           application/json image/svg+xml;
gzip_vary on;                   # emits Vary: Accept-Encoding

# Varnish VCL - normalize Accept-Encoding before the cache lookup so
# Varnish stores one gzip variant per URL instead of many combinations.
# Brotli negotiation is handled by Nginx in front of Varnish.

sub vcl_recv {
    if (req.http.Accept-Encoding) {
        if (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
        } else {
            unset req.http.Accept-Encoding;
        }
    }
}

sub vcl_backend_response {
    # Ensure downstream caches respect the encoding variant
    if (beresp.http.Content-Encoding) {
        set beresp.http.Vary = "Accept-Encoding";
    }
}

9. Gzip vs. Brotli im direkten Vergleich

Beide Verfahren haben klar unterschiedliche Stärken. Die folgende Übersicht fasst zusammen, wann welches Verfahren die bessere Wahl ist.

Dimension Gzip Brotli Praxisrelevanz
Algorithmus-Basis DEFLATE: LZ77 (32 KB Fenster) + Huffman LZ77-Variante (16 MB Fenster) + Kontextmodellierung + Wörterbuch Größeres Fenster findet mehr Wiederholungen
Kompressionsrate (Text) Baseline Typisch 15-25 % kleiner Effekt stärker bei repetitivem Boilerplate
CPU-Kosten bei Maximalstufe Level 9: moderat Qualität 11: sehr hoch Brotli 11 nur für Build-Zeit geeignet
Bestes Einsatzszenario Dynamische On-the-fly-Antworten Statische Build-Artefakte, vorkomprimiert Kombination beider Verfahren üblich
Server-/Browser-Support Universell, seit Jahrzehnten Standard Breite Unterstützung, aber Gzip-Fallback nötig Immer beide Varianten ausliefern

In der Praxis schließen sich beide Verfahren nicht aus, sondern ergänzen sich: Brotli für vorkomprimierte statische Assets, Gzip als garantiert kompatibler Fallback und als günstigere Option für dynamische Antworten, bei denen jede Millisekunde Rechenzeit zählt. Wer nur eines von beiden ausliefert, verschenkt entweder Kompatibilität oder Kompressionsrate.

Mironsoft

Kompressions-Setup, Nginx-Tuning und Caching-Architektur für Magento-Shops

Brotli und Gzip sauber ausgeliefert?

Wir analysieren die Kompressionskonfiguration eures Magento-Stacks, richten Pre-Compression im Build-Prozess ein und konfigurieren Nginx sowie Varnish so, dass jede Antwort mit der optimalen Encoding-Variante ausgeliefert wird.

Build-Pipeline-Audit

Pre-Compression für .br und .gz in Vite/Webpack einrichten

Nginx-Konfiguration

brotli_static, gzip_static und passende Comp-Level für Live-Traffic

Varnish-Abstimmung

Accept-Encoding-Normalisierung und Cache-Varianten sauber trennen

10. Zusammenfassung

Die Kompression von HTML, CSS und JS löst ein konkretes Netzwerkproblem: redundanter Text kostet unnötige Übertragungszeit. Gzip komprimiert über LZ77 mit einem 32-KB-Fenster und Huffman-Codierung und ist universell unterstützt - der verlässliche Standard. Brotli geht mit einem 16-MB-Fenster, feinerer Kontextmodellierung und einem eingebauten Wörterbuch aus rund 13.000 Web-typischen Strings weiter und erreicht dadurch typischerweise 15 bis 25 % kleinere Ausgaben bei Text-Assets. Der Preis dafür ist CPU-Zeit: Brotli-Qualität 11 gehört ausschließlich in den Build-Prozess, niemals in den Live-Request-Pfad.

Die richtige Architektur trennt beide Einsatzfälle konsequent: statische, versionierte Assets werden beim Build mit maximaler Qualität vorkomprimiert und über brotli_static/gzip_static direkt ausgeliefert, dynamisches Magento-HTML wird zur Laufzeit mit einer bewusst günstigeren Stufe komprimiert. Varnish normalisiert Accept-Encoding vor dem Cache-Lookup, damit nicht für jede Client-Kombination eine eigene Cache-Variante entsteht, während Nginx die eigentliche Brotli-Aushandlung übernimmt.

Brotli vs. Gzip - Das Wichtigste auf einen Blick

Algorithmus

Gzip: LZ77 (32 KB Fenster) + Huffman. Brotli: 16-MB-Fenster + Kontextmodellierung + 13.000-Wörter-Wörterbuch.

Kompressionsrate

Brotli typischerweise 15-25 % kleiner als Gzip bei HTML-, CSS- und JS-Assets.

CPU-Kosten

Brotli-Qualität 11 nur für den Build-Prozess. Dynamisch niedrige Stufen wie Qualität 4-5 verwenden.

Serverkonfiguration

brotli_static + gzip_static in Nginx. Varnish normalisiert Accept-Encoding vor dem Cache-Lookup.

11. FAQ: Brotli vs. Gzip

1Was ist der Hauptunterschied zwischen Brotli und Gzip?
Brotli nutzt ein 16-MB-Fenster statt 32 KB und ein eingebautes Wörterbuch mit rund 13.000 web-typischen Strings. Dadurch typischerweise 15-25 % kleinere Ausgaben als Gzip.
2Wie funktioniert die LZ77-Komprimierung bei Gzip?
LZ77 ersetzt Wiederholungen innerhalb eines 32-KB-Fensters durch Distanz-Länge-Paare. Huffman-Codierung komprimiert danach mit kürzeren Bitmustern für häufige Werte.
3Was ist das statische Wörterbuch von Brotli?
Rund 13.000 Strings aus realen Web-Inhalten, u.a. HTML-Tags, CSS-Eigenschaften und JS-Schlüsselwörter. Ermöglicht starke Kompression auch bei kurzen Dateien ohne interne Wiederholung.
4Wie viel kleiner sind Dateien mit Brotli wirklich?
Meist 15-25 % kleiner bei HTML, CSS und JS. Generischer Boilerplate-Code profitiert stärker als individueller Anwendungscode.
5Warum ist Brotli-Qualität 11 für Live-Traffic ungeeignet?
Zehn- bis hundertmal langsamer als Gzip -9 für nur wenige Prozentpunkte Zusatzgewinn. Gehört ausschließlich in den Build-Prozess, nicht in den Request-Pfad.
6Wie erkennt der Server das unterstützte Verfahren?
Über den Accept-Encoding-Header des Clients. Der Server antwortet mit Content-Encoding und setzt Vary: Accept-Encoding für Caches.
7Pre-Compression vs. On-the-fly-Kompression?
Pre-Compression erzeugt .br/.gz beim Build mit maximaler Qualität. On-the-fly komprimiert live bei jeder Anfrage, mit günstigerer Stufe.
8Statische Assets vs. dynamisches HTML bei Magento?
Statische, versionierte Assets eignen sich für Pre-Compression mit maximaler Qualität. Dynamisches HTML wird zur Laufzeit mit günstigerer Stufe komprimiert.
9Warum galt Varnish als Problem für Brotli?
Varnish unterstützt kein natives Brotli und normalisiert Accept-Encoding meist auf gzip. Nginx übernimmt die Brotli-Aushandlung vor oder hinter Varnish.
10Welche Nginx-Direktiven sind relevant?
brotli_static/gzip_static für vorkomprimierte Dateien, brotli_comp_level/gzip_comp_level für On-the-fly-Fälle, gzip_vary für den korrekten Vary-Header.