Eine Website wird selten in einem Zug langsam. Sie wird es Stück für Stück: ein neues Karussell auf der Startseite, ein zusätzliches Tracking-Skript, ein Hero-Bild in voller Auflösung, eine Bibliothek, die jemand für eine Kleinigkeit einbindet. Jede einzelne Änderung wirkt harmlos, doch in Summe rutschen die mühsam erreichten Core Web Vitals wieder aus dem grünen Bereich – meist unbemerkt, weil nach dem Deploy niemand misst. Genau hier setzt ein Performance-Budget an: Es legt vorab feste Obergrenzen für Ladezeit, Reaktionsschnelligkeit, Layoutstabilität und Seitengewicht fest und lässt eine Maschine bei jeder Änderung prüfen, ob diese Grenzen eingehalten werden. Als budget.json-Regel in Lighthouse CI wandert diese Prüfung direkt in den Entwicklungsprozess und stoppt den Build automatisch, sobald ein Wert die Schwelle reißt. Dass sich der Aufwand lohnt, zeigt schon eine Zahl aus der Praxis: Nur 62 Prozent (Web Almanac 2025) der mobilen Websites erreichen überhaupt ein gutes LCP unter 2,5 Sekunden. Dieser Beitrag zeigt, wie ein Budget aufgebaut ist, wie Lighthouse CI daraus einen Torwächter im Pull Request macht und wie Sie die Schwellen so kalibrieren, dass sie streng, aber nicht zickig sind. In unserer Core-Web-Vitals-Optimierung ist ein solches Budget der Baustein, der das Ergebnis dauerhaft absichert.
Das Wichtigste in Kürze
- Ein Performance-Budget legt Obergrenzen vorab fest – für Ergebnis-Metriken wie LCP, INP und CLS und für Mengengerüste wie Kilobyte JavaScript oder Anzahl der Anfragen. Die Metriken schützen das Erlebnis, die Mengengrenzen schützen die Metriken.
- Als gut gelten ein LCP unter 2,5 Sekunden (web.dev), ein INP unter 200 Millisekunden (web.dev) und ein CLS unter 0,1 (web.dev) am 75. Perzentil – doch nur 62 Prozent (Web Almanac 2025) der mobilen Websites erreichen ein gutes LCP.
- Die Regeldatei budget.json beschreibt Zeit- und Ressourcengrenzen je Pfad und liegt versioniert im Repository. Zum Gate wird sie erst durch Lighthouse CI: Verletzt eine Messung eine als Fehler markierte Schwelle, endet der Lauf mit Fehlercode.
- Schwellen brauchen einen bewussten Puffer und den Median aus mehreren Läufen. Ein Gate, das schon bei Messrauschen rot wird, verliert das Vertrauen des Teams und wird pauschal durchgewunken – dann ist es wertlos, obwohl es technisch funktioniert.
- Das Budget misst im Labor und ersetzt die Felddaten nicht: Das INP ist dort nur über die Total Blocking Time annäherbar, das CLS wird nur bis zum Ende des Seitenaufbaus erfasst. Erst die Feldmessung zeigt, was echte Nutzer erleben.
Warum jeder Deploy die Core Web Vitals unbemerkt verschlechtert
Performance ist keine Eigenschaft, die man einmal herstellt und die dann bleibt. Sie ist ein Zustand, der bei jeder Codeänderung neu auf dem Spiel steht. Das Tückische an Performance-Regressionen ist, dass sie schleichend passieren und keinen sichtbaren Fehler erzeugen: Die Seite funktioniert weiterhin, sie lädt nur etwas langsamer, reagiert etwas träger oder verschiebt beim Aufbau kurz das Layout. Für die Person, die die Änderung eingecheckt hat, sieht auf dem schnellen Büro-Rechner mit stabilem Netz alles gut aus. Erst die echten Nutzer auf Mittelklasse-Smartphones im Mobilfunknetz spüren die Verschlechterung – und die tauchen in keinem Fehlerbericht auf, sondern springen einfach ab.
Die wirtschaftlichen Folgen sind gut belegt. Schon 0,1 Sekunden (Deloitte) schnellere Ladezeit steigerten in einer branchenübergreifenden Analyse die Conversions im Handel um 8,4 Prozent (Deloitte). Umgekehrt steigt die Wahrscheinlichkeit, dass ein Nutzer die Seite wieder verlässt, um 32 Prozent (Google/SOASTA), wenn die Ladezeit von einer auf drei Sekunden wächst. Und die Conversion-Rate sinkt laut einer Auswertung von Millionen Seitenaufrufen um rund 4,4 Prozent (Portent) mit jeder zusätzlichen Sekunde in den ersten fünf Sekunden. Jede unbemerkte Regression kostet also messbar Geld. Der klassische Gegenmittel-Reflex – alle paar Monate ein großes Performance-Audit – kommt für diese kleinen, kontinuierlichen Verschlechterungen zu spät: Bis zum nächsten Audit haben sich Dutzende Mini-Regressionen aufsummiert, und niemand weiß mehr, welche Änderung welchen Anteil hatte.
Ein Performance-Budget dreht die Logik um. Statt Verschlechterungen im Nachhinein zu suchen, verhindert es sie beim Entstehen. Es macht Performance zu einer Bedingung, die jede Änderung erfüllen muss, bevor sie in den Hauptzweig darf – so wie automatisierte Tests dafür sorgen, dass eine Änderung keine bestehende Funktion zerstört. Wer die drei Core Web Vitals im Zusammenhang verstehen möchte, findet die Einordnung im Beitrag zu den Core Web Vitals 2026; hier geht es darum, wie man ihre Einhaltung dauerhaft erzwingt.
Was ein Performance-Budget ist und was es misst
Ein Performance-Budget ist eine Sammlung von Obergrenzen, die eine Seite nicht überschreiten darf. Diese Grenzen betreffen zwei Arten von Werten. Zum einen die Ergebnis-Metriken, also das, was der Nutzer erlebt: das Largest Contentful Paint (LCP) für die Ladezeit, das Interaction to Next Paint (INP) für die Reaktionsschnelligkeit und das Cumulative Layout Shift (CLS) für die visuelle Stabilität. Als gut gelten ein LCP unter 2,5 Sekunden (web.dev), ein INP unter 200 Millisekunden (web.dev) und ein CLS unter 0,1 (web.dev), jeweils gemessen am 75. Perzentil (web.dev) der Seitenaufrufe. Zum anderen die Mengengerüst-Budgets, die Ursachen begrenzen: wie viele Kilobyte JavaScript, Bilder oder Schriften eine Seite laden darf und wie viele Anfragen sie absetzt.
Der Unterschied ist wichtig. Ergebnis-Metriken sagen, ob es dem Nutzer zu langsam ist; Mengengerüst-Budgets sagen, warum. Ein JavaScript-Budget von beispielsweise 400 Kilobyte pro Seite fängt eine Regression oft früher ab als eine Metrik, weil zusätzlicher Code in aller Regel zuerst das Gewicht erhöht und erst danach die Reaktionszeit. Beide Budget-Arten ergänzen sich deshalb: Die Metriken schützen das Erlebnis, die Mengengrenzen schützen die Metriken. Wie man ein reines Ressourcen-Budget für Skripte und Medien aufsetzt und pflegt, vertieft der Beitrag zu den JavaScript-Performance-Budgets.
Labor- und Feldmetriken im Budget
budget.json: die Regeldatei für Ressourcen und Metriken
Das Herzstück ist eine schlichte Textdatei namens budget.json. Sie beschreibt in einem klar lesbaren Format, welche Obergrenzen gelten – getrennt nach Zeit-Metriken (timings) und Ressourcen-Mengen (resourceSizes und resourceCounts). Jede Regel bezieht sich auf einen Pfad, sodass sich unterschiedliche Seitentypen unterschiedlich behandeln lassen. Die Datei liegt im Repository neben dem Code und wird damit selbst versioniert: Jede Änderung am Budget ist nachvollziehbar, und das Budget durchläuft dieselben Reviews wie der Rest des Projekts.
[
{
"path": "/*",
"timings": [
{ "metric": "largest-contentful-paint", "budget": 2500 },
{ "metric": "total-blocking-time", "budget": 200 },
{ "metric": "speed-index", "budget": 3400 }
],
"resourceSizes": [
{ "resourceType": "script", "budget": 400 },
{ "resourceType": "image", "budget": 500 },
{ "resourceType": "total", "budget": 1000 }
]
}
]In diesem Beispiel darf das LCP höchstens 2.500 Millisekunden betragen, die Total Blocking Time höchstens 200 Millisekunden, und das ausgelieferte JavaScript höchstens 400 Kilobyte. Lighthouse liest diese Datei, vergleicht die gemessenen Werte mit den Budgets und markiert jeden Posten, der darüber liegt, als über Budget. Das allein stoppt allerdings noch keinen Build – es erzeugt nur einen Bericht. Damit aus dem Bericht ein echtes Gate wird, braucht es einen zweiten Baustein: Lighthouse CI.
Lighthouse CI als Torwächter im Pull Request
Lighthouse CI (die quelloffene Werkzeugkette GoogleChrome/lighthouse-ci) ist die Brücke zwischen einem Lighthouse-Bericht und Ihrer Pipeline. Es besteht aus drei Schritten: collect sammelt die Messungen, indem es Lighthouse mehrfach gegen die definierten Adressen laufen lässt; assert vergleicht die Ergebnisse mit festgelegten Schwellen; und upload legt die Berichte ab, wahlweise auf einem eigenen LHCI-Server für den Langzeitverlauf. Entscheidend für das Gate ist der assert-Schritt: Verletzt eine Messung eine als error markierte Schwelle, beendet sich das Werkzeug mit einem Fehlercode ungleich null. In jeder CI-Umgebung – ob GitHub Actions, GitLab CI oder eine andere Pipeline – bedeutet ein solcher Fehlercode: Der Lauf ist rot, der Check schlägt fehl, der Merge wird blockiert.
{
"ci": {
"collect": {
"url": ["https://example.com/"],
"numberOfRuns": 3
},
"assert": {
"assertions": {
"categories:performance": ["error", { "minScore": 0.9 }],
"largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
"total-blocking-time": ["error", { "maxNumericValue": 200 }],
"cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }]
}
}
}
}Diese Konfiguration verlangt eine Performance-Note von mindestens 0,9 und setzt harte Grenzen für LCP, TBT und CLS. Man kann die budget.json und die Assertions kombinieren: Die eine deckt die Ressourcen-Mengen ab, die andere die Ergebnis-Metriken und die Gesamtnote. Wichtig ist, dass die Prüfung nicht auf dem Rechner der Entwicklerin läuft, sondern in der Pipeline – reproduzierbar, mit gedrosseltem Netz und gedrosselter CPU, wie es Lighthouse für die mobile Messung standardmäßig annimmt. Nur so entspricht das Laborergebnis grob dem, was Nutzer auf schwächeren Geräten erleben.
Ein Gate pro Pull Request
Lighthouse CI läuft automatisch bei jedem Pull Request, noch bevor der Code den Hauptzweig erreicht. Reißt ein Budget, wird die Prüfung rot und der Merge lässt sich nicht abschließen, bis die Ursache behoben ist.
Median aus mehreren Läufen
Statt einer einzelnen, verrauschten Messung bildet Lighthouse CI den Median aus mehreren Durchläufen. Das dämpft zufällige Ausreißer und macht die Schwelle verlässlich genug, um sie hart zu erzwingen.
Verlauf statt Momentaufnahme
Der optionale LHCI-Server speichert jeden Lauf und zeigt den zeitlichen Verlauf. So wird sichtbar, ob sich eine Metrik über viele kleine Schritte langsam vom Ziel entfernt, lange bevor sie das Budget reißt.
Schwellen richtig kalibrieren: streng, aber nicht zickig
Ein Budget ist nur so nützlich wie seine Schwellen. Sind sie zu locker, rutschen Regressionen durch und das Gate wiegt in falscher Sicherheit. Sind sie zu streng oder zu nah an der aktuellen Messung, schlägt der Build schon bei normalem Messrauschen fehl – und ein Team, das ständig rote Läufe ohne echten Grund sieht, gewöhnt sich an, sie zu ignorieren. Ein gutes Budget beginnt deshalb bei den offiziellen Zielwerten und lässt einen kleinen, bewussten Puffer. Der Median aus mehreren Läufen und ein Warn-Level unterhalb der harten Fehlergrenze helfen, das Rauschen von echten Verschlechterungen zu trennen.
| Metrik | Gutes Ziel | Budget im CI (Vorschlag) | Typische Regressionsursache |
|---|---|---|---|
| LCP | unter 2,5 s (web.dev) | max. 2,5 s, Warnung ab 2,2 s | Neues Hero-Bild ohne Preload, langsamere Serverantwort |
| INP / TBT | unter 200 ms (web.dev) | TBT max. 200 ms | Zusätzliches Drittanbieter-Skript, ungeteilte lange Aufgabe |
| CLS | unter 0,1 (web.dev) | max. 0,1 | Anzeige oder Banner ohne reservierten Platz |
| JavaScript-Gewicht | schlank halten | max. 400 KB pro Seite | Neue Bibliothek, doppelt gebündeltes Framework |
| Gesamtgewicht | so klein wie möglich | max. 1 MB pro Seite | Unkomprimierte Medien, viele Drittanbieter-Anfragen |
Wichtig ist außerdem, das Budget pro Seitentyp zu differenzieren. Die Startseite, eine Kategorieseite, eine Produktseite und ein Blogartikel haben völlig verschiedene Realitäten: Was für eine textlastige Artikelseite großzügig ist, wäre für eine bildlastige Produktseite unrealistisch eng. Deshalb erlaubt die budget.json unterschiedliche Regeln je Pfad. Ein häufiger Auslöser für gerissene Budgets sind Drittanbieter-Skripte, die sich über Tag-Manager unbemerkt einschleichen; wie man diese Last gezielt reduziert, behandelt der Beitrag zum Entschlacken von Drittanbieter-Skripten.
Ein zu zickiges Gate ist schlimmer als keines
Vom roten Build zur grünen Pipeline: der Ablauf
In der Praxis fügt sich das Budget in den ganz normalen Entwicklungsablauf ein. Jemand öffnet einen Pull Request, die Pipeline startet, baut die Seite, lässt Lighthouse CI gegen die relevanten Adressen laufen und vergleicht die Ergebnisse mit dem Budget. Bleiben alle Werte im Rahmen, wird der Check grün und die Änderung kann zusammengeführt werden. Reißt ein Budget, wird der Check rot, und der Bericht zeigt genau, welche Metrik oder welche Ressource über der Grenze liegt. Die verantwortliche Person sieht das noch vor dem Merge und kann die Ursache im überschaubaren Diff des Pull Requests suchen, statt später im gewachsenen Gesamtsystem.
- Ein Budget je Seitentyp festlegen – Startseite, Kategorie, Produkt und Artikel haben unterschiedliche Realitäten
- budget.json und die Lighthouse-CI-Konfiguration ins Repository legen, damit jede Änderung sie durchläuft
- Die Prüfung als Pflicht-Check im Pull Request verankern, sodass ein roter Lauf den Merge blockiert
- Mehrere Läufe pro Messung nehmen und den Median werten, um zufälliges Rauschen auszublenden
- Bei einem gerissenen Budget die betroffene Metrik im Bericht öffnen und die Ursache im Diff suchen
- Das Budget regelmäßig nachziehen: Wird eine Seite dauerhaft schneller, wird die Schwelle strenger
Der Kern in einem Satz
Der Nebeneffekt ist kulturell so wertvoll wie technisch. Sobald das Gate steht, wird Performance zur geteilten Verantwortung des ganzen Teams statt zur Aufgabe einer einzelnen Person, die alle paar Monate aufräumt. Weil die Rückmeldung sofort im Pull Request kommt, lernt jede Entwicklerin unmittelbar, welche Muster teuer sind – ein spät geladenes Hero-Bild, ein ungeteilter langer Task, eine schwere Bibliothek. Wie man solche langen Aufgaben mit scheduler.yield gezielt aufteilt und Bremsen einzelner Frames aufspürt, zeigen zwei vertiefende Beiträge zur Interaktivität.
Was ein Budget nicht ersetzt: die Felddaten
So wirksam ein CI-Budget ist – es misst im Labor, nicht bei echten Nutzern. Das Labor liefert reproduzierbare Werte unter kontrollierten Bedingungen und ist deshalb ideal, um Regressionen zwischen zwei Ständen zu erkennen. Was echte Menschen auf ihren Geräten und in ihren Netzen erleben, zeigen aber nur Felddaten. Und der Unterschied ist wirtschaftlich relevant: Wächst die Ladezeit von einer auf fünf Sekunden, steigt die Absprungwahrscheinlichkeit um 90 Prozent (Google/SOASTA), und im Reisesegment brachten schon 0,1 Sekunden schnelleres Laden 10,1 Prozent (Deloitte) mehr Conversions. Diese Effekte entstehen im Feld, nicht im Labor.
Deshalb gehören Labor-Budget und Feldmessung zusammen: Das Budget im CI verhindert, dass eine Regression überhaupt live geht; die Feldmessung bestätigt, dass sich die Werte auch bei echten Nutzern halten. Wie sich Labor- und Felddaten – also Lighthouse-Läufe, RUM und die CrUX-Daten von Google – sinnvoll zu einer Gesamtstrategie verbinden lassen, vertieft der Beitrag zu RUM, CrUX und Performance-Budgets. Und weil das INP im Labor nur über die TBT annäherbar ist, lohnt der ergänzende Blick auf die INP-Optimierung im Detail.
Ein Budget im CI verändert die Kultur im Team: Performance ist keine einmalige Aktion mehr, die nach ein paar Monaten verpufft, sondern eine Bedingung, die jeder Pull Request erfüllen muss – automatisch geprüft, bevor irgendjemand es vergisst.
Genau so gehen wir bei der Einrichtung vor: Wir bestimmen die kritischen Seitentypen, kalibrieren realistische Budgets für LCP, INP und CLS, verankern Lighthouse CI als Pflicht-Check in Ihrer Pipeline und begleiten das Team, bis rote Läufe als hilfreiches Signal und nicht als Störung verstanden werden. Welche Leistungen dazugehören, zeigt unsere Übersicht der Performance-Leistungen; für die konkreten Frontend-Hebel, mit denen sich ein gerissenes Budget wieder einfangen lässt, hilft die Frontend-Optimierung.
Verwandte Artikel
Tempo festschreiben: Performance in der Ausschreibung
Wie Ladezeit zum Abnahmekriterium wird: Zielwert, Messmethode, Datenquelle und Nachweiszeitpunkt je Kennzahl – und was das Werkvertragsrecht daraus macht.
View Transitions API: Nahtlose Seitenwechsel im Shop
Native, GPU-beschleunigte Seitenwechsel im Shop ohne JavaScript-Framework: Wie Cross-Document View Transitions den Sprung von Kategorie zu Produkt glätten.
Lange Tasks aufteilen: INP mit scheduler.yield senken
Lange JavaScript-Tasks über 50 ms mit scheduler.yield() in Häppchen zerlegen, den Hauptthread zwischen den Chunks freigeben und den INP unter 200 ms halten.