Use efficient cache lifetimes in Lighthouse: so behebst du es
Lighthouse 13 listet jede Datei auf, die die Browser deiner Besucher weniger als 30 Tage wiederverwenden können. Was das auf der nächsten Seite und beim wiederkehrenden Besuch kostet, und der Fix pro Server und Plattform.
Schadet „Use efficient cache lifetimes“ deinem Lighthouse-Score?
Lighthouse markiert jede statische Datei mit einer Cache-Lebensdauer unter 30 Tagen im Insight „Use efficient cache lifetimes“ („Eine lange Cache-Lebensdauer kann wiederholte Aufrufe deiner Seite beschleunigen“). Vor Lighthouse 13 hieß die Meldung „Serve static assets with an efficient cache policy“, in älteren PageSpeed Insights „Leverage browser caching“. Für deinen Score zählt das nicht und es kann ihn auch nicht verändern: Lighthouse lädt Seiten immer mit leerem Cache. Richte längere Lebensdauern auf deinem Server, im CDN oder Caching-Plugin ein.
Table of Contents!
Was bedeutet „Use efficient cache lifetimes“ in Lighthouse?
Die Beschreibung von Lighthouse lautet: „Eine lange Cache-Lebensdauer kann wiederholte Aufrufe deiner Seite beschleunigen. Mehr über Caching erfahren.“
Lighthouse listet jedes Skript, Stylesheet, jeden Font sowie jede Bild-, Video- und Audiodatei mit einer Cache-Lebensdauer unter 30 Tagen oder ganz ohne Lebensdauer auf. Die Lebensdauer ist das max-age im Cache-Control-Header der Datei oder die Zeitspanne bis zu ihrem Expires-Datum. Dateien fremder Domains werden genauso aufgeführt wie deine eigenen.
Lighthouse lässt Dateien weg, deren Cache-Control no-cache, no-store, private oder must-revalidate enthält – unabhängig vom max-age: Das gilt als Entscheidung gegen Caching. Dateien mit max-age=0 werden ebenfalls ignoriert, und die HTML-Seite selbst listet Lighthouse nie auf.

Eine Seite, die Google Tag Manager, GA4 und das Meta-Pixel lädt. Google sendet seine Tags als private, daher wird von den dreien nur das Meta-Pixel gelistet. Lighthouse 13.5.0, simuliertes Throttling wie in PageSpeed Insights.
Wie funktioniert Browser-Caching?
Der Browser speichert eine Datei zusammen mit ihrer Lebensdauer. Beim nächsten Seitenaufruf oder dem nächsten Besuch prüft er zuerst seine gespeicherte Kopie:
- Innerhalb der Lebensdauer: Der Browser nutzt seine Kopie und sendet überhaupt keinen Request. Das ist der einzige Fall ohne Wartezeit auf den Server.
- Lebensdauer abgelaufen: Der Browser fragt beim Server nach, ob sich die Datei geändert hat – anhand des ETag oder des Last-Modified-Datums, das er mit der Datei erhalten hat. Hat sie sich nicht geändert, antwortet der Server mit 304 Not Modified, ohne die Datei mitzuschicken. Das spart den Download. Jede Datei kostet aber trotzdem einen Roundtrip zum Server, und die Seite kann erst rendern, wenn der Server für jedes Stylesheet geantwortet hat.
- Lebensdauer abgelaufen und kein ETag oder Last-Modified: Der Browser lädt die Datei erneut herunter.
| Header der Datei | Nächster Aufruf in Chrome |
|---|---|
max-age=31536000 | Ein Jahr lang aus dem Cache |
max-age=14400 | 4 Stunden aus dem Cache, danach ein 304 |
no-cache | Jedes Mal ein 304 |
no-store | Jedes Mal neu heruntergeladen |
Ein normaler Reload in Chrome prüft Dateien nicht erneut, solange ihre Lebensdauer noch läuft. Firefox und Safari tun das, außer die Datei enthält immutable im Cache-Control.
Seit Chrome 86 hat jede Website ihren eigenen Cache. Einen Font oder eine jQuery-Datei, die deine Besucher bereits auf einer anderen Website heruntergeladen haben, lädt der Browser auf deiner Seite erneut herunter – selbst von derselben URL. Die Lebensdauer bei Drittanbietern hilft also nur auf deiner eigenen Website, für die nächste Seite und den wiederkehrenden Besuch. Und „das haben ohnehin schon alle im Cache“ ist kein Grund mehr, Fonts von Google zu laden (hoste sie selbst).
Der Browser-Cache und der Cache deines CDNs sind zwei verschiedene Dinge – genau wie der Page-Cache eines WordPress-Caching-Plugins. Ein CDN oder Page-Cache speichert eine Kopie, damit dein Server die Seite nicht für jeden Besucher neu ausliefern oder zusammenbauen muss. Das verkürzt die TTFB (Cache-Dauer). Der Browser-Cache spart den kompletten Request ein, für einen einzelnen Besucher. Bei diesem Insight geht es ausschließlich um den Browser-Cache. Ein aktiver Page-Cache behebt die Meldung also nicht.
Verbessert eine längere Cache-Lebensdauer LCP und FCP?
FCP und LCP beim ersten Besuch
Kein Unterschied. Auf einer WooCommerce-Produktseite auf einem Smartphone über Slow 4G lag der erste Paint bei 2,13 s und der LCP bei 2,26 s – bei jedem Header, von gar keinem bis zu einem Jahr: Beim ersten Besuch ist noch nichts im Cache. Lighthouse und PageSpeed Insights laden Seiten immer genau so. Diesen Insight zu beheben, verändert deinen Lighthouse-Score und deine Metriken nicht – selbst wenn Lighthouse ihn rot anzeigt und FCP- und LCP-Einsparungen danebenstehen.

Keine Lebensdauer

Cloudflares 4 Stunden

Ein Jahr

no-store
Dieselbe Produktseite mit vier verschiedenen Cache-Headern für ihre Dateien. Lighthouse 13.5.0, Mobile, simuliertes Throttling.
FCP und LCP auf der nächsten Seite und beim wiederkehrenden Besuch
Der erste Paint (FCP) in Sekunden, verglichen mit 2,13 s beim ersten Besuch:
| Cache-Header | Nächste Seite | Eine Woche später |
|---|---|---|
| Ein Jahr | 0,79 | 0,78 |
| 4 Stunden | 0,80 | 1,94 |
no-cache | 1,93 | 1,94 |
no-store | 2,11 | 2,12 |
- Der Gewinn entsteht durch Dateien innerhalb ihrer Lebensdauer. Eine Woche später lag der erste Paint bei der Seite mit einem Jahr Lebensdauer bei 0,78 s – etwa ein Drittel des ersten Besuchs. Was bleibt, ist das Warten auf das HTML. Beim wiederkehrenden Besuch trat der LCP, das Produktfoto, bei jedem Header im selben Moment auf wie der erste Paint, außer bei no-store (2,24 s).
- Mit 304-Statuscodes war der Folgebesuch fast so langsam wie der Erstbesuch. Ohne Lebensdauer antworteten eine Woche später alle 13 shop-eigenen Dateien mit 304: 1 kB über das Netzwerk statt 404 kB. Trotzdem lag der erste Paint erst bei 1,94 s – nur 0,19 s schneller als der komplette Neudownload.
- Kurze Lebensdauern decken den aktuellen Besuch ab, laufen aber vor dem nächsten ab. Cloudflares 4 Stunden lieferten die nächste Seite aus dem Cache aus. Eine Woche später waren 304-Requests nötig. Nur die Einstellung auf ein Jahr deckte beides ab.
- no-cache und no-store verlangsamen jede Seite. Sie bremsten die nächste Seite von 0,79 s auf 1,93 s bzw. 2,11 s aus.

Keine Lebensdauer, eine Woche später

Ein Jahr Lebensdauer, eine Woche später
Beide Seiten bei 0,8 s auf dem gedrosselten Smartphone.
Auf einer echten Slow-4G-Verbindung dauert jeder Aufruf länger; die Reihenfolge zwischen den Headern bleibt gleich. Über Fast 4G renderte die Seite mit einem Jahr Lebensdauer beim wiederkehrenden Besuch bei 0,52 s. Der Wiederbesuch mit 304-Requests dauerte 0,85 s – genauso lange wie der Erstbesuch auf dieser Verbindung.
Wann kannst du „Use efficient cache lifetimes“ ignorieren?
Wenn Lighthouse deine eigenen Dateien aufführt und deine Besucher Tage oder Wochen später wiederkommen, behebe es: Es braucht eine einzige Regel auf dem Server und kostet beim Laden der Seite nichts. Ignoriere es, wenn:
- jede gelistete Datei auf einer fremden Domain liegt oder von deiner Plattform ausgeliefert wird (siehe unten); auf Shopify ist das immer so;
- sich dein CSS und JavaScript unter demselben Dateinamen ändern und du keine Versionierung anhängen kannst: Dann ist eine kurze Lebensdauer die richtige Wahl, und Lighthouse listet diese Dateien weiterhin auf;
- fast jeder Besucher nur eine Seite ansieht und nie wiederkommt, wie etwa auf einer Landingpage für eine Werbekampagne: Niemand nutzt den Cache.
Wie misst du den Effekt von Cache-Lebensdauern in deinen Field Data?
Deine Field Data vermischen Erstbesuche mit Folgeseiten und wiederkehrenden Besuchen. Gruppiere in CoreDash den LCP auf Mobile nach Repeat Visitor, und danach die TTFB genauso:


CoreDash auf einer Demo-Website, acme-pagespeed.com: Mobile, p75.
Wiederkehrende Besucher haben einen LCP von 0,65 s, neue Besucher 1,74 s. Dieser Abstand geht nicht allein auf das Konto des Caches: Wiederkehrende Besucher erhalten auch das erste Byte schneller – 323 ms gegenüber 0,87 s. Oft liegt das daran, dass der Browser bereits eine Verbindung zu deinem Server aufgebaut hat. Ziehe also die TTFB vom LCP ab. Nach dem ersten Byte warten wiederkehrende Besucher 0,33 s und neue Besucher 0,87 s. Diese 0,54 s spart der Cache grob ein, also etwa die Hälfte des Unterschieds. Das schnellere erste Byte macht die andere Hälfte aus.
Um die nächste Seite eines Besuchs isoliert zu betrachten, gruppiere nach Navigation Origin: Same Origin bedeutet, dass der Besucher von einer anderen Seite deiner Website kam. CrUX fasst all diese Besuche in einem einzigen p75-Wert pro Seite oder Domain zusammen und kann diese Aufteilung daher nicht abbilden.
Wie prüfst du die Cache-Header einer Datei in DevTools?
Öffne das Network-Panel und stelle sicher, dass Disable cache deaktiviert ist (die DevTools-Netzwerkeinstellungen erklären, wann du es aktivieren solltest). Lade deine Seite und klicke dann weiter auf eine zweite Seite. Die Spalten Status und Size zeigen, was mit jeder Datei passiert ist:
- (disk cache) oder (memory cache) bei Size: Aus dem Cache geladen, kein Request.
- 304 bei Status: Der Browser hat beim Server nachgefragt und keine Datei zurückbekommen.
- 200 mit Größenangabe: Erneut heruntergeladen.

Keine Lebensdauer: 304 für jede Datei

Ein Jahr: aus dem Disk-Cache
Der wiederkehrende Besuch eine Woche später im Network-Panel, Slow 4G.
Klicke auf eine Datei und öffne den Reiter Headers. Unter Response Headers zeigen cache-control und expires die vom Server gesendete Lebensdauer an, etag und last-modified die Werte, mit denen der Browser nachfragen kann. Über die Kommandozeile:
curl -sI https://www.example.com/wp-content/themes/acme/style.css | grep -iE "cache-control|expires|etag|last-modified" Das Performance-Panel bietet denselben Insight. Zeichne einen Reload auf und öffne „Use efficient cache lifetimes“ in der Insights-Seitenleiste: Dort werden die Dateien aufgelistet und im Network-Track hervorgehoben. Eine Datei ohne Lebensdauer wird dort mit 0 ms angezeigt, in Lighthouse als None. Ausschlaggebend sind die Header: Eine Datei, die aus dem Cache geladen wurde, taucht also trotzdem auf, wenn ihre Lebensdauer zu kurz ist.

Wie behebst du „Use efficient cache lifetimes“?
Die Domain jeder von Lighthouse gelisteten Datei verrät dir, wer den Header setzt: Auf deiner eigenen Domain ist das dein Server, dein Hoster oder dein CDN; auf jeder anderen Domain der jeweilige Drittanbieter.
nginx, Apache, IIS und Caddy
Auf deinem eigenen Server genügt eine Regel pro Dateityp, um die Lebensdauer festzulegen. Diese Regeln vergeben ein Jahr inklusive immutable: Nutze sie für Bilder sowie für CSS, JavaScript und Fonts, sobald deren URLs eine Version enthalten (welche Lebensdauer für welche Datei). Unter nginx:
location ~* \.(?:css|js|mjs|woff2|svg|png|jpe?g|gif|webp|avif|ico)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
} Füge das in den server-Block ein, der diese Dateien von der Festplatte ausliefert. Hat deine Konfiguration bereits einen location-Block für diese Dateiendungen, ergänze stattdessen dort die Zeile mit add_header: nginx nutzt immer nur den ersten passenden Regex-Location-Block. Entferne eventuelle expires-Zeilen daraus, sonst erhalten die Dateien zwei Cache-Control-Header. Ein add_header innerhalb eines location-Blocks sorgt dafür, dass nginx alle add_header-Direktiven des übergeordneten server-Blocks für diese Dateien verwirft. Kopiere die add_header-Zeilen des server-Blocks (zum Beispiel deinen HSTS-Header) daher ebenfalls in diesen location-Block.
In Apache gehört das in die .htaccess:
<IfModule mod_headers.c>
<FilesMatch "\.(css|js|mjs|woff2|svg|png|jpe?g|gif|webp|avif|ico)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
</IfModule> FilesMatch orientiert sich am Dateinamen, sodass von PHP generierte Seiten ihre eigenen Header behalten. Listet Lighthouse die Dateien danach immer noch auf, wendet dein Server die Regel nicht an: Entweder ist mod_headers deaktiviert, oder dein Hoster liefert diese Dateien über einen separaten Server aus, der die .htaccess ignoriert. Frage in dem Fall deinen Hoster.
Der IIS sendet standardmäßig gar keine Lebensdauer. Setze den Header in der web.config, beschränkt auf den Ordner mit deinen statischen Dateien:
<configuration>
<location path="assets">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="public, max-age=31536000, immutable" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
</configuration> Unter Caddy:
@static path *.css *.js *.mjs *.woff2 *.svg *.png *.jpg *.jpeg *.gif *.webp *.avif *.ico
header @static Cache-Control "public, max-age=31536000, immutable" WordPress
WordPress selbst liefert für Inhalte in /wp-content/ oder /wp-includes/ keine Lebensdauer aus: Das entscheiden dein Hoster, dein Server oder ein Plugin. Kinsta, WP Engine, WordPress VIP und WordPress.com liefern bereits ein Jahr aus: Wenn du dort hostest, liegen die von Lighthouse gelisteten Dateien meist auf anderen Domains (siehe unten). Die Meldung taucht typischerweise auf Shared-Hosting mit Apache auf, das keine Lebensdauer mitsendet, auf selbst verwalteten Servern mit nginx sowie hinter Cloudflares Standardeinstellung. Bei den Caching-Plugins gilt:
- WP Rocket schreibt auf Apache- und LiteSpeed-Servern mod_expires-Regeln in die .htaccess: ein Jahr für CSS und JavaScript, vier Monate für Bilder und Fonts. Unter nginx passiert gar nichts: Füge die obige nginx-Regel hinzu oder wende dich an deinen Hoster.
- LiteSpeed Cache hat den Browser-Cache standardmäßig deaktiviert. Aktiviere ihn unter LiteSpeed Cache, Cache, Browser; danach sendet das Plugin ein Jahr.
- W3 Total Cache hat den Browser-Cache standardmäßig aktiviert. Unter nginx schreibt das Plugin eine nginx.conf, die du selbst in deine Serverkonfiguration einbinden musst.
WordPress hängt an jedes geladene Stylesheet und Skript ein ?ver= an: standardmäßig die WordPress-Version oder die Version, die Theme oder Plugin übergeben. Das ändert sich nur bei einem Update. Bearbeitest du dein eigenes CSS, ohne die Version anzupassen, bleibt die URL identisch – und wiederkehrende Besucher behalten das alte CSS für die gesamte Cache-Lebensdauer. Binde deine eigenen Dateien stattdessen mit dem Änderungszeitpunkt als Version ein, damit sich die URL bei jeder Änderung erneuert:
add_action( 'wp_enqueue_scripts', function () {
$file = '/css/custom.css';
wp_enqueue_style( 'acme-custom', get_stylesheet_directory_uri() . $file, array(), filemtime( get_stylesheet_directory() . $file ) );
} ); Uploads besitzen keine Version. Lädst du eine Datei erneut hoch, vergibt WordPress einen neuen Dateinamen (photo-1.jpg). Ein Jahr ist hier also sicher – es sei denn, ein Plugin ersetzt Medien unter demselben Namen.
Cloudflare und andere CDNs
Cloudflares Browser Cache TTL steht standardmäßig in jedem Tarif auf 4 Stunden. Sendet dein Server keine oder eine kürzere Lebensdauer, liefert Cloudflare 4 Stunden aus – und Lighthouse listet die Datei mit „4h“ auf. Richte die Lebensdauern auf deinem Server ein und stelle die Browser Cache TTL (unter Caching, Configuration) auf Respect Existing Headers um. Alternativ erstellst du eine Cache Rule für deine statischen Dateitypen, die die Browser-TTL festlegt. Setze die zonenweite Einstellung nicht pauschal auf ein Jahr: Sie greift dann für jede Datei, die Cloudflare mit kürzerem Header ausliefert, unversioniertes CSS eingeschlossen. Mehr zu den weiteren Einstellungen findest du unter Cloudflare für die Core Web Vitals konfigurieren.
CloudFront und Fastly leiten die Header deines Servers direkt an den Browser weiter; ihre TTL-Einstellungen ändern nur, wie lange das CDN seine eigene Kopie vorhält. Bei Bunny legt eine Edge Rule mit Override Browser Cache Time die Lebensdauer pro Dateiendung fest.
Shopify
Shopify vergibt für deine Theme-Dateien, Uploads und Produktbilder bereits ein ganzes Jahr (public, max-age=31557600), und die Header von Shopify kannst du nicht ändern. Was Lighthouse bei Shopify beanstandet, stammt von Shopify selbst oder deinen Apps: die dynamischen Checkout-Buttons (portable-wallets, 5 Minuten, auf deiner eigenen Domain unter /cdn/shopifycloud/), der Loader shop-js (30 Minuten) und der Web Pixels Manager (60 Sekunden). Hier gibt es nichts zu beheben. Ignoriere die Meldung.
Next.js und andere Build-Tools
Next.js versieht alles unter /_next/static/ mit einem Jahr inklusive immutable – das lässt sich nicht überschreiben. Dateien in public/ erhalten max-age=0 (auf Vercel mit must-revalidate) und /_next/image sendet must-revalidate, weshalb der Insight beide überspringt. Auf einer Next.js-Website stammen die von Lighthouse gelisteten Dateien von Drittanbietern oder von einem vorgeschalteten Proxy oder CDN, das die Header umschreibt. Für Dateien in public/, deren Name sich mit dem Inhalt ändert, hinterlegst du ein Jahr in der next.config.js:
module.exports = {
async headers() {
return [{
source: '/fonts/:path*',
headers: [{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' }],
}]
},
} Lass auf jedem anderen Stack den Bundler einen Hash in die Dateinamen einfügen (app.3f9a1c.js), damit jede Änderung eine neue URL erzeugt. Liefere diese Dateien dann mit einem Jahr Lebensdauer aus.
Dateien von Drittanbietern und Plattformen, die du nicht ändern kannst
Drittanbieter halten die Lebensdauer ihrer Skripte kurz, um sie auf allen Websites gleichzeitig aktualisieren zu können – und ihre Header kannst du nicht anpassen. Lighthouse listet diese Skripte oft auf, jeweils mit der vom Anbieter vorgegebenen Lebensdauer:
- Meta-Pixel (fbevents.js): 20 Minuten
- Hotjar: 60 Sekunden
- Altes analytics.js von Google Analytics: 2 Stunden
- Google Maps (maps/api/js): 30 Minuten
- Stripe (js.stripe.com/v3): 2 Minuten
- Cloudflares eigene Skripte auf deiner Domain (email-decode.min.js, Rocket Loader): 2 Tage
Lass diese Dateien in Ruhe. Hoste Loader wie fbevents.js oder gtag.js nicht selbst, nur um deinen eigenen Header darauf zu bekommen: Deine Kopie erhält dann keine Updates des Anbieters mehr. Was du tun kannst:
- Lade Bibliotheken über ein öffentliches CDN mit einer exakten Versionsnummer in der URL. jsDelivr vergibt für swiper@11 sieben Tage und für eine exakt festgelegte Version ein ganzes Jahr. Oder hoste diese fixierte Version selbst mit deinem eigenen Header.
- Deaktiviere nicht benötigte Cloudflare-Funktionen wie die E-Mail-Adressen-Verschleierung.
- Entferne Tags, die niemand mehr braucht.
Welche Cache-Lebensdauer für welche Datei
- CSS, JavaScript und Fonts mit Version oder Hash in der URL: Ein Jahr mit immutable:
Cache-Control: public, max-age=31536000, immutable. Eine neue Version bedeutet eine neue URL, der Browser lädt sie also sofort neu herunter. - Bilder: Derselbe Header. Gib einem geänderten Bild einen neuen Dateinamen, dann sieht niemand mehr die alte Version.
- CSS, JavaScript und Fonts ohne Version: Ergänze zuerst eine Versionierung (siehe die Schritte oben für WordPress und Build-Tools). Bis dahin halte die Lebensdauer kurz und akzeptiere, dass Lighthouse sie auflistet: Bei einer langen Lebensdauer für ein Stylesheet, das sich unter demselben Namen ändert, erhalten wiederkehrende Besucher dein neues HTML mit dem alten CSS.
- Das HTML:
Cache-Control: no-cacheoder ein kurzes max-age, da Besucher bei einer langen Lebensdauer auf einer veralteten Seite festsitzen würden. - Niemals no-store, no-cache oder must-revalidate auf statische Dateien anwenden, nur um die Meldung loszuwerden: Jeder Seitenaufruf prüft oder lädt sonst jede Datei wieder neu herunter (siehe oben zur Folgeseite).
Wie prüfst du, ob deine neuen Cache-Lebensdauern funktionieren?
Prüfe zuerst den Header der Datei mit curl oder im Reiter Headers (siehe oben): Dort sollte das neue max-age stehen. Führe Lighthouse danach auf Mobile aus. Die Dateien tauchen nicht mehr auf, und Score sowie Metriken bleiben unverändert – genau wie in den vier Testberichten oben. Auf der Produktseite lag der Score von Durchlauf zu Durchlauf mal bei 96, mal bei 80. Das hatte rein gar nichts mit dem Header zu tun. Ein abweichender Score nach dem Fix sagt dir also absolut nichts über den Cache.
Wiederkehrende Besucher in CoreDash zeigen das Ergebnis als Erste, innerhalb weniger Tage – sobald sie zurückkehren und die Dateien mit der neuen Lebensdauer erhalten. CrUX und die Search Console bilden die letzten 28 Tage ab: Zwei Wochen nach dem Fix spiegelt die Hälfte der Daten also immer noch den alten Stand wider.
Bist du unsicher, welche der aufgeführten Dateien du selbst beheben kannst oder ob wiederkehrende Besucher auf bereits geladene Dateien warten? In einer Core-Web-Vitals-Power-Hour gehen wir deine Header und deine Field Data gemeinsam durch – und du erhältst die fertigen Regeln für deinen Server noch vor Ende des Gesprächs.
CoreDash hab ich für meine eigenen Audits gebaut.
Unter 1KB. In der EU gehostet. Kein Cookie-Banner. Jetzt mit MCP.
CoreDash kostenlos testen