Use efficient cache lifetimes in Lighthouse: zo los je het op

Lighthouse 13 toont elk bestand dat de browsers van je bezoekers korter dan 30 dagen kunnen hergebruiken. Wat dat kost bij de volgende pagina en het terugkerende bezoek, en de fix per server en platform.

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-10-17

Is "Use efficient cache lifetimes" slecht voor je Lighthouse-score?

Lighthouse markeert elk statisch bestand met een cache-levensduur korter dan 30 dagen in het insight Use efficient cache lifetimes ("A long cache lifetime can speed up repeat visits to your page"), vóór Lighthouse 13 "Serve static assets with an efficient cache policy" genoemd en in oudere PageSpeed Insights "Leverage browser caching". Het telt niet mee voor je score en kan die ook niet veranderen: Lighthouse laadt altijd met een lege cache. Stel een langere levensduur in op je server, CDN of caching-plugin.

Wat betekent Use efficient cache lifetimes in Lighthouse?

De omschrijving van Lighthouse luidt: "A long cache lifetime can speed up repeat visits to your page. Learn more about caching."

Lighthouse toont elk script, elke stylesheet, font, afbeelding, video en elk audiobestand met een cache-levensduur korter dan 30 dagen, of helemaal zonder levensduur. Die levensduur is de max-age in de Cache-Control-header van het bestand, of anders de tijd tot de Expires-datum. Bestanden van andere domeinen staan er net zo tussen als die van jezelf.

Bevat de Cache-Control van een bestand no-cache, no-store, private of must-revalidate, dan laat Lighthouse het weg, ongeacht de max-age: dat ziet het als een bewuste keuze om niet te cachen. Bestanden met max-age=0 laat het ook weg, en de HTML-pagina zelf staat er nooit tussen.

Het insight Use efficient cache lifetimes in Lighthouse, rood, geschatte besparing van 444 KiB: dertien eigen bestanden van de shop met een cache-TTL van None en Meta's fbevents.js met 20 minuten; Google Tag Manager en gtag.js staan er niet tussen.

Een pagina die Google Tag Manager, GA4 en de Meta Pixel laadt. Google verstuurt zijn tags als private, waardoor van de drie alleen de Meta Pixel in de lijst staat. Lighthouse 13.5.0, gesimuleerde throttling zoals in PageSpeed Insights.

Hoe werkt browser caching?

De browser slaat een bestand op samen met de levensduur. Bij een volgende pagina of een volgend bezoek kijkt hij eerst naar de opgeslagen kopie:

  • Binnen de levensduur: de browser gebruikt zijn eigen kopie en verstuurt helemaal geen request. Alleen in dit geval hoef je niet op de server te wachten.
  • Levensduur verstreken: de browser vraagt met de meegestuurde ETag of Last-Modified-datum aan de server of het bestand gewijzigd is. Is dat niet zo, dan antwoordt de server met 304 Not Modified, zonder het bestand. Dat scheelt een download, maar elk bestand kost nog steeds een round trip naar de server, en de pagina kan pas renderen als de server voor elke stylesheet heeft geantwoord.
  • Levensduur verstreken en geen ETag of Last-Modified: de browser downloadt het bestand opnieuw.
Header op het bestandVolgende weergave in Chrome
max-age=31536000Een jaar lang uit de cache
max-age=144004 uur lang uit de cache, daarna een 304
no-cacheElke keer een 304
no-storeElke keer opnieuw gedownload

Bij een normale reload controleert Chrome bestanden die nog binnen hun levensduur vallen niet opnieuw. Firefox en Safari doen dat wel, tenzij het bestand immutable in de Cache-Control heeft staan.

Sinds Chrome 86 heeft elke site een eigen cache. Een font of jQuery-bestand dat een bezoeker al op een andere site heeft gedownload, wordt op jouw site opnieuw gedownload, zelfs vanaf exact dezelfde URL. De levensduur van een third-party helpt dus alleen op je eigen site, bij de volgende pagina en het terugkerende bezoek. "Iedereen heeft het toch al gecachet" is dan ook geen reden meer om fonts via Google te laden (host ze zelf).

De browsercache en de cache van je CDN zijn twee verschillende dingen, net als de page cache van een WordPress-cachingplugin. Een CDN of page cache bewaart een kopie zodat je server die niet voor elke bezoeker hoeft te bouwen of te versturen. Dat verkort de TTFB (cache duration). De browsercache bespaart het hele request, voor één bezoeker. Dit insight gaat alleen over de browsercache; een page cache die al aan staat, lost deze melding dus niet op.

Verbetert een langere cache-levensduur de LCP en FCP?

FCP en LCP bij een eerste bezoek

Geen verschil. Op een WooCommerce-productpagina, op een telefoon via Slow 4G, was de first paint bij elke header 2,13 s en kwam de LCP uit op 2,26 s, van geen enkele header tot een jaar: bij een eerste bezoek staat er immers nog niets in de cache. Lighthouse en PageSpeed Insights laden een pagina altijd alleen op deze manier. Los je dit insight op, dan veranderen je Lighthouse-score en metrics nooit, zelfs niet als Lighthouse het in het rood toont met FCP- en LCP-besparingen erbij.

Lighthouse op telefoonbreedte: score 96, LCP 2,4 s, en Use efficient cache lifetimes in het rood met 345 KiB geschatte besparing, voor bestanden zonder cache-levensduur.

Geen levensduur

Lighthouse op telefoonbreedte: dezelfde score 96 en LCP 2,4 s, het insight in het rood met 235 KiB, voor bestanden die vier uur gecachet zijn.

De 4 uur van Cloudflare

Lighthouse op telefoonbreedte: dezelfde score 96 en LCP 2,4 s, het insight geslaagd, voor bestanden die een jaar gecachet zijn.

Eén jaar

Lighthouse op telefoonbreedte: dezelfde score 96 en LCP 2,4 s, het insight geslaagd, voor bestanden die met no-store worden verstuurd en nooit worden gecachet.

no-store

Dezelfde productpagina met vier verschillende cache-headers op de bestanden. Lighthouse 13.5.0, mobiel, gesimuleerde throttling.

FCP en LCP bij een volgende pagina en een terugkerend bezoek

De first paint (FCP) in seconden, vergeleken met 2,13 s bij het eerste bezoek:

Cache-headerVolgende paginaEen week later
een jaar0,790,78
4 uur0,801,94
no-cache1,931,94
no-store2,112,12
  • De winst zit in bestanden binnen hun levensduur. Een week later had de pagina met een levensduur van een jaar zijn first paint al op 0,78 s, ongeveer een derde van het eerste bezoek. Het enige wat overblijft, is het wachten op de HTML. Bij het terugkerende bezoek viel de LCP, de productfoto, bij elke header op hetzelfde moment als de first paint, behalve bij no-store (2,24 s).
  • Met 304's was het terugkerende bezoek bijna net zo traag als een eerste bezoek. Zonder levensduur kwamen een week later alle 13 eigen bestanden van de shop terug als 304: 1 kB over het netwerk in plaats van 404 kB, en alsnog een first paint op 1,94 s, slechts 0,19 s sneller dan alles opnieuw downloaden.
  • Korte levensduren dekken het actieve bezoek en verlopen vóór de terugkeer. De 4 uur van Cloudflare serveerde de volgende pagina uit de cache. Een week later waren er 304's nodig. Alleen de instelling van een jaar dekte beide.
  • no-cache en no-store vertragen elke pagina. Ze brachten de volgende pagina van 0,79 s naar 1,93 s en 2,11 s.
Een telefoonscherm dat na 0,8 seconden bij een terugkerend bezoek een week later nog steeds wit is, terwijl elk bestand bij de server wordt gecontroleerd.

Geen levensduur, een week later

Dezelfde productpagina volledig getoond na 0,8 seconden bij een terugkerend bezoek een week later, met elk bestand uit de browsercache.

Een jaar levensduur, een week later

Beide pagina's op 0,8 s op de gethrottlede telefoon.

Op een echte Slow 4G-verbinding duurt elke weergave langer; de onderlinge volgorde van de headers blijft gelijk. Op Fast 4G had een levensduur van een jaar bij het terugkerende bezoek een first paint op 0,52 s, en duurde de terugkeer met 304's 0,85 s: net zo lang als het eerste bezoek op die verbinding.

Wanneer kun je Use efficient cache lifetimes negeren?

Toont Lighthouse je eigen bestanden en komen bezoekers dagen of weken later terug, los het dan op: het vraagt één regel op de server en kost niets tijdens het laden van de pagina. Laat het zitten als:

  • elk vermeld bestand op een ander domein staat of door je platform wordt geserveerd (zie hieronder); op Shopify is dat altijd zo;
  • je CSS en JavaScript onder dezelfde bestandsnaam wijzigen en je geen versie kunt toevoegen: een korte levensduur is dan de juiste keuze, en Lighthouse blijft die bestanden tonen;
  • vrijwel elke bezoeker maar één pagina bekijkt en nooit meer terugkomt, zoals bij een landingspagina voor een advertentiecampagne: niemand gebruikt de cache.

Hoe meet je het effect van cache-levensduren in je field data?

In je field data lopen eerste bezoeken, volgende pagina's en terugkerende bezoeken door elkaar. Groepeer in CoreDash de LCP op mobiel op Repeat Visitor, en doe daarna hetzelfde voor TTFB:

CoreDash, LCP op mobiel gegroepeerd op Repeat Visitor: terugkerende bezoekers 0,65 seconden op p75, nieuwe bezoekers 1,74 seconden, beide beoordeeld als goed. CoreDash, TTFB op mobiel gegroepeerd op Repeat Visitor: terugkerende bezoekers 323 ms op p75, beoordeeld als goed; nieuwe bezoekers 0,87 seconden, beoordeeld als improve.

CoreDash op een demosite, acme-pagespeed.com: mobiel, p75.

Terugkerende bezoekers hebben een LCP van 0,65 s, nieuwe bezoekers 1,74 s. Niet dat hele gat komt door de cache: terugkerende bezoekers ontvangen de eerste byte ook sneller, 323 ms tegenover 0,87 s, vaak omdat de browser al een open verbinding met je server heeft. Trek de TTFB daarom af van de LCP. Na de eerste byte wachten terugkerende bezoekers 0,33 s en nieuwe bezoekers 0,87 s. Die 0,54 s is grofweg wat de cache bespaart, ongeveer de helft van het verschil; de snellere eerste byte is de andere helft.

Wil je de volgende pagina van een bezoek los bekijken, groepeer dan op Navigation Origin: same origin betekent dat de bezoeker van een andere pagina op je site kwam. CrUX gooit al deze bezoeken op één hoop in één p75 per pagina of per site, en kan deze splitsing dus niet tonen.

Hoe controleer je de cache-headers van een bestand in DevTools?

Open het Network-paneel en zorg dat Disable cache uit staat (de DevTools-netwerkinstellingen leggen uit wanneer je dit aanzet). Laad je pagina en klik door naar een tweede pagina. De kolommen Status en Size laten zien wat er met elk bestand is gebeurd:

  • (disk cache) of (memory cache) bij Size: uit de cache gehaald, geen request.
  • 304 bij Status: de browser vroeg het aan de server en kreeg geen bestand terug.
  • 200 met een bestandsgrootte: opnieuw gedownload.
Chrome DevTools Network-paneel bij een terugkerend bezoek: elke stylesheet, script, font en de foto gaven een 304 zonder bytes terug, elk met een round trip van ongeveer 600 ms.

Geen levensduur: 304 voor elk bestand

Chrome DevTools Network-paneel bij een terugkerend bezoek: de HTML gedownload, elk ander bestand binnen 1 tot 3 ms geserveerd vanuit de disk cache.

Eén jaar: vanuit de disk cache

Het terugkerende bezoek een week later in het Network-paneel, Slow 4G.

Klik op een bestand en open het tabblad Headers. Onder Response Headers tonen cache-control en expires de levensduur die je server meestuurde; etag en last-modified tonen waarmee de browser controleert op wijzigingen. Vanaf de command line:

curl -sI https://www.example.com/wp-content/themes/acme/style.css | grep -iE "cache-control|expires|etag|last-modified"

Het Performance-paneel bevat hetzelfde insight. Neem een reload op en open Use efficient cache lifetimes in de Insights-sidebar: je ziet de bestanden in een lijst en rood omlijnd in de Network-track. Een bestand zonder levensduur staat daar als 0 ms, en in Lighthouse als None. Dit kijkt puur naar de headers; een bestand dat uit de cache kwam, staat er dus alsnog tussen als de levensduur kort is.

Chrome DevTools Performance-paneel met het insight Use efficient cache lifetimes geopend: de bestanden van de shop vermeld met een cache-TTL van 0 ms en rood omlijnd in de Network-track.

Hoe los je Use efficient cache lifetimes op?

Het domein van elk bestand dat Lighthouse toont, verraadt wie de header instelt: op je eigen domein is dat je server, je host of je CDN; op elk ander domein is het de leverancier van dat bestand.

nginx, Apache, IIS en Caddy

Op je eigen server stel je de levensduur in met één regel per bestandstype. Onderstaande regels stellen een jaar in, met immutable: gebruik ze voor afbeeldingen, en voor CSS, JavaScript en fonts zodra hun URL's een versie bevatten (welke levensduur voor welk bestand). In nginx:

location ~* \.(?:css|js|mjs|woff2|svg|png|jpe?g|gif|webp|avif|ico)$ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

Plaats dit in het server-block dat deze bestanden van schijf serveert. Heeft je configuratie al een location voor deze extensies, voeg de add_header-regel dan daaraan toe; nginx gebruikt namelijk alleen de eerste matchende regex-location. Verwijder eventuele expires-regels daaruit, anders krijgen de bestanden twee Cache-Control-headers. Een add_header binnen een location zorgt dat nginx alle add_header-regels uit het server-block voor die bestanden negeert. Kopieer de add_header-regels van het server-block (zoals je HSTS-header) daarom ook naar deze location.

Zet dit voor Apache in .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 kijkt naar de bestandsnaam, waardoor pagina's die PHP opbouwt hun eigen headers behouden. Toont Lighthouse de bestanden daarna nog steeds, dan past je server de regel niet toe: mod_headers staat uit, of je host serveert deze bestanden vanaf een andere server die .htaccess negeert. Vraag dit na bij je host.

IIS stuurt standaard helemaal geen levensduur mee. Stel de header in via web.config, beperkt tot de map met je statische bestanden:

<configuration>
  <location path="assets">
    <system.webServer>
      <httpProtocol>
        <customHeaders>
          <add name="Cache-Control" value="public, max-age=31536000, immutable" />
        </customHeaders>
      </httpProtocol>
    </system.webServer>
  </location>
</configuration>

In 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 zelf stuurt geen levensduur mee voor bestanden in /wp-content/ of /wp-includes/: dat bepaalt je host, je server of een plugin. Kinsta, WP Engine, WordPress VIP en WordPress.com sturen standaard al een jaar mee: host je daar, dan staan de bestanden die Lighthouse toont meestal op andere domeinen (zie hieronder). De melding verschijnt vooral bij shared hosting op Apache die geen levensduur meestuurt, op een eigen nginx-server en achter de standaardinstelling van Cloudflare. Bij de caching-plugins:

  • WP Rocket schrijft mod_expires-regels naar .htaccess op Apache- en LiteSpeed-servers: een jaar voor CSS en JavaScript, vier maanden voor afbeeldingen en fonts. Op nginx doet de plugin niets: voeg de bovenstaande nginx-regel toe of vraag het je host.
  • LiteSpeed Cache heeft Browser Cache standaard uitgeschakeld staan. Zet dit aan onder LiteSpeed Cache, Cache, Browser; daarna stuurt het een jaar mee.
  • W3 Total Cache heeft Browser Cache standaard ingeschakeld staan. Op nginx genereert de plugin een nginx.conf die je zelf moet toevoegen aan je serverconfiguratie.

WordPress plakt ?ver= achter elke stylesheet en elk script dat het laadt: standaard de WordPress-versie, of de versie die het thema of de plugin meegeeft. Dat verandert alleen bij een update. Pas je je eigen CSS aan zonder de versie te verhogen, dan blijft de URL gelijk en blijven terugkerende bezoekers de oude CSS houden zolang de levensduur loopt. Laad je eigen bestanden daarom in met hun wijzigingstijd als versie, zodat de URL bij elke bewerking verandert:

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 hebben geen versie. Upload je een bestand opnieuw, dan geeft WordPress het een nieuwe naam (photo-1.jpg). Een jaar is daarvoor dus veilig, tenzij een plugin media onder dezelfde naam overschrijft.

Cloudflare en andere CDN's

De Browser Cache TTL van Cloudflare staat op elk plan standaard op 4 uur. Stuurt je server geen of een kortere levensduur mee, dan maakt Cloudflare er 4 uur van en toont Lighthouse het bestand als "4h". Stel de levensduur in op je server en zet Browser Cache TTL (Caching, Configuration) op Respect Existing Headers. Of maak voor je statische bestandstypen een Cache Rule aan die de browser-TTL instelt. Verhoog de instelling voor de hele zone niet naar een jaar: die geldt dan voor elk bestand dat Cloudflare met een kortere header serveert, inclusief CSS zonder versie. Meer over de overige instellingen lees je in configure Cloudflare for the Core Web Vitals.

CloudFront en Fastly geven de header van je server direct door aan de browser; hun TTL-instellingen bepalen alleen hoe lang het CDN de eigen kopie bewaart. Bij Bunny stelt een Edge Rule met Override Browser Cache Time de levensduur per bestandsextensie in.

Shopify

Shopify geeft je themabestanden, uploads en productafbeeldingen standaard al een jaar mee (public, max-age=31557600), en die headers van Shopify kun je niet aanpassen. Wat Lighthouse op Shopify toont, is afkomstig van Shopify zelf en je apps: de dynamische checkout-knoppen (portable-wallets, 5 minuten, op je eigen domein onder /cdn/shopifycloud/), de shop-js loader (30 minuten) en de web pixels manager (60 seconden). Er valt niets te fixen. Negeer de melding.

Next.js en andere build-tools

Next.js geeft alles onder /_next/static/ een jaar mee met immutable; dat kun je niet overschrijven. Bestanden in public/ krijgen max-age=0 (op Vercel met must-revalidate) en /_next/image stuurt must-revalidate mee, waardoor het insight beide overslaat. Op een Next.js-site zijn de bestanden die Lighthouse toont afkomstig van third-parties, of van een proxy of CDN ervoor die de headers herschrijft. Voor bestanden in public/ waarvan de naam mee verandert met de inhoud, stel je in next.config.js een jaar in:

module.exports = {
  async headers() {
    return [{
      source: '/fonts/:path*',
      headers: [{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' }],
    }]
  },
}

Laat bij elke andere stack de bundler een hash in de bestandsnamen zetten (app.3f9a1c.js), zodat elke wijziging een nieuwe URL krijgt. Geef die bestanden vervolgens een jaar mee.

Third-party- en platformbestanden die je niet kunt aanpassen

Een leverancier houdt de levensduur van zijn script kort om het op alle sites tegelijk te kunnen updaten, en die headers kun je niet veranderen. Lighthouse toont deze bestanden vaak, met de levensduur die de leverancier meegeeft:

  • Meta Pixel (fbevents.js): 20 minuten
  • Hotjar: 60 seconden
  • Het oude analytics.js van Google Analytics: 2 uur
  • Google Maps (maps/api/js): 30 minuten
  • Stripe (js.stripe.com/v3): 2 minuten
  • De eigen scripts van Cloudflare op je domein (email-decode.min.js, Rocket Loader): 2 dagen

Laat dit zo. Ga een loader zoals fbevents.js of gtag.js niet zelf hosten om er een eigen header op te krijgen: je kopie ontvangt dan geen updates van de leverancier meer. Wat je wel kunt doen:

  • Laad een library in vanaf een publiek CDN met een exacte versie in de URL. jsDelivr geeft swiper@11 zeven dagen en een exacte versie een jaar. Of host die vastgezette versie zelf, onder je eigen header.
  • Schakel functies van Cloudflare uit die je niet gebruikt, zoals Email Address Obfuscation.
  • Verwijder tags die niemand meer gebruikt.

Welke cache-levensduur stel je in voor welk bestand

  • CSS, JavaScript en fonts met een versie of hash in de URL: een jaar, met immutable: Cache-Control: public, max-age=31536000, immutable. Een nieuwe versie betekent een nieuwe URL, dus de browser haalt die direct op.
  • Afbeeldingen: dezelfde header. Geef een gewijzigde afbeelding een nieuwe bestandsnaam, dan krijgt niemand ooit de oude te zien.
  • CSS, JavaScript en fonts zonder versie: voeg die eerst toe (zie de stappen voor WordPress en build-tools hierboven). Zolang dat niet kan, houd je de levensduur kort en accepteer je dat Lighthouse ze toont: bij een lange levensduur op een stylesheet die onder dezelfde naam wijzigt, krijgen terugkerende bezoekers je nieuwe HTML met de oude CSS te zien.
  • De HTML: Cache-Control: no-cache of een korte max-age, want met een lange levensduur blijven bezoekers op een verouderde pagina hangen.
  • Gebruik nooit no-store, no-cache of must-revalidate op statische bestanden om van de melding af te zijn: elke paginaweergave controleert of downloadt elk bestand dan opnieuw (zie de volgende pagina hierboven).

Hoe controleer je of je nieuwe cache-levensduren werken?

Controleer eerst de header op het bestand met curl of via het Headers-tabblad (hierboven): daar hoort de nieuwe max-age te staan. Draai daarna Lighthouse op mobiel. De bestanden staan niet meer in de lijst en de score en metrics blijven gelijk, zoals in de vier rapporten hierboven. Op de productpagina kwam de score van run tot run uit op 96 of 80, en welke het werd had niets met de header te maken. Een andere score na de fix zegt je dus niets over de cache.

In CoreDash zie je het bij terugkerende bezoekers al binnen een paar dagen terug, zodra ze terugkomen en de bestanden met de nieuwe levensduur ophalen. CrUX en Search Console tonen de afgelopen 28 dagen: twee weken na de fix bestaat de helft van die data dus nog uit de oude site.

Weet je niet zeker welke bestanden uit de lijst van jou zijn om te fixen, of vraag je je af of terugkerende bezoekers wachten op bestanden die ze al hebben? In een Core Web Vitals power hour lopen we samen door je headers en field data heen, en krijg je de regels voor je server voor we de call afronden.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

 

Ik lever code, geen rapport.

Ik schuif 1 of 2 sprints aan bij je team. Ik zet de monitoring op zodat je metrics groen blijven als ik weg ben.

Bel me
Use efficient cache lifetimes in Lighthouse: zo los je het op Core Web Vitals Use efficient cache lifetimes in Lighthouse: zo los je het op