Stale While Revalidate Explained for Web Performance

You've probably seen this already. A returning visitor opens a page, the content appears immediately, and the browser fetches a newer copy in the background instead of making them wait on a full revalidation. That's stale while revalidate, one of the cleanest ways to reduce perceived delay on repeat views without turning freshness into a guessing game.

If you want to see how caching choices show up in real loading behavior, the fastest next step is to test them with the PageSpeed Plus WordPress plugin. It gives you a practical way to watch performance changes instead of relying on gut feel alone.

Table of Contents

Why Stale While Revalidate Matters for Faster Pages

A lot of slow pages aren't slow because the content is huge. They're slow because the browser waits on one extra round trip before it can render something that's already known locally. Stale while revalidate changes that tradeoff, so a repeat visitor sees the cached response right away while the cache refreshes behind the scenes.

That matters most when the origin is flaky, busy, or farther away than the user expects. It also matters on pages where a brief freshness gap is acceptable, such as versioned assets, fonts, or images that don't change every minute. For a broader performance mindset, the same idea fits well with the practical advice in Nerdify's guide to website performance tips for startups, especially where every extra wait step adds friction.

Practical rule: use SWR when instant delivery is more valuable to the visitor than forcing an immediate origin check.

The rest of this guide walks from the header syntax to service worker behavior, then into CDN differences, Core Web Vitals impact, and testing. It stays close to what the cache does, because that's where people usually get confused.

The Lifecycle Behind Stale While Revalidate

The cleanest mental model is a fridge. Fresh is the milk inside its safe date, stale is the milk that's still usable for a short grace period, and rotten is the point where you throw it out. HTTP caching works the same way, except the freshness boundary comes from max-age, not a printed label.

RFC 5861 standardized stale-while-revalidate in May 2010 and defined it as an HTTP cache-control extension that lets caches serve a response after it becomes stale while revalidating it asynchronously in the background. The directive only makes sense when paired with max-age, because max-age defines the fresh window and the extra SWR value defines the grace window after that. In the canonical example, Cache-Control: max-age=600, stale-while-revalidate=30, the response is fresh for 600 seconds and can still be served for another 30 seconds, for a total staleness window of 630 seconds before the cache must stop serving stale content absent other information, as described in RFC 5861.

What happens at each stage

A response served under SWR is still technically stale in HTTP terms. The original Internet-Draft says it carries a non-zero Age header and a warning header, which is a useful reminder that this is a bounded grace period, not a loophole for serving old content forever. If the cache doesn't revalidate before the stale window ends, it must not keep serving it stale without more information, as stated in the draft for stale-while-revalidate.

State What the cache does What the user sees
Fresh Serves from cache immediately Fast response
Stale but within SWR window Serves stale and revalidates in background Fast response, updated later
Beyond SWR window Fetches before serving Waiting on origin

That lifecycle is the key to reading any Cache-Control header correctly. Once you can spot the fresh window and the grace window, you can predict whether the next request will be instant, backgrounded, or blocked.

How Browsers Service Workers and CDNs Differ

The same directive behaves differently depending on where it lives. In a browser HTTP cache, SWR is mostly a declarative response to the header, and it works best on subresources such as CSS, JavaScript, and images. HTML can use it too, but the risk of showing slightly old page content is usually more noticeable there than on a stylesheet.

A service worker is different because the browser won't invent background refresh logic for you. The developer writes the behavior in a fetch handler, usually by checking the Cache API first, returning that response immediately, and kicking off a separate network request to update the cache for later visits. That means the background refresh is not a platform feature, it's your code.

Practical rule: if you control the fetch event, you control the tradeoff, but you also own the failure modes.

CDNs sit in a third category. They interpret the origin's Cache-Control headers, but the platform decides whether revalidation is synchronous or asynchronous. Cloudflare's February 2026 changelog entry for asynchronous stale while revalidate shows that major edge platforms are still evolving this behavior, which is a good reminder that SWR at the edge isn't one single implementation. If you work with proxy layers too, the caching behavior discussed in PageSpeed Plus's Varnish proxy cache guide is worth comparing against the browser and edge model.

The important distinction is simple. In browsers, the network cache refreshes. In service workers, your JavaScript refreshes. In CDNs, the edge platform refreshes. Same phrase, different machinery.

Header and Service Worker Examples in Practice

A long grace window makes sense for assets that are expensive to regenerate but safe to serve slightly stale. A header such as Cache-Control: max-age=60, stale-while-revalidate=3600 gives you a 60-second fresh period and a 3,600-second background refresh window, so the asset can stay usable for up to 3,660 seconds total while the cache refills asynchronously, as shown in this caching example. If the content behind that asset changes in a way users must see right away, learn about cache purging strategies so you can clear stale copies instead of waiting for the SWR window to run out.

That setup matters most on the first request after expiry. The user gets a fast response, the cache starts refreshing in the background, and the next visit usually lands on the newer object without another wait.

Header-driven flow

A browser or CDN reads the response age, serves it while the object is still inside the SWR window, and begins revalidation in the background. The request stays fast for the user, while freshness is restored after the fact. That ordering is the point of the directive.

The exact behavior can vary by platform. Some caches revalidate asynchronously, others refresh more synchronously, and some edge systems expose their own controls around how stale content is served.

Service worker flow

A service worker puts the same idea into code. You decide which requests to cache, which cache key to use, and whether a stale response should be shown before the network finishes.

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cached => {
      const networkFetch = fetch(event.request).then(response => {
        return caches.open('runtime').then(cache => {
          cache.put(event.request, response.clone())
          return response
        })
      })
      return cached || networkFetch
    })
  )
})

With this pattern, the user gets the cached response immediately when one exists. The network request still runs, but it updates the cache for the next visit instead of delaying the current one. That difference matters because the browser does not invent this behavior for you, your fetch handler does.

If the asset is versioned, browser-managed HTTP caching is usually the easier path. If you need custom cache keys, fallback logic, or a different refresh rule for specific requests, the service worker gives you that control, but you also own the edge cases and the cache eviction plan.

Impact on Core Web Vitals and Real User Metrics

SWR helps because it removes a blocking wait from the critical path on repeat visits. That usually improves Time to First Byte and can make Largest Contentful Paint feel much faster when the main resource is already cached. It also helps Interaction to Next Paint on returning visits, because the page is less likely to stall while waiting for a synchronous refresh.

Google's internal test on ad scripts is a strong real-world signal here. Over 2 weeks on 5.2 billion Google display ad impressions, the experiment showed a 0.3% increase in ad impressions, a 0.5% increase in revenue, a 2% increase in early ad script loads within 500 ms of page load start, and a 1.1% increase in successful ad script loads overall, according to Google's stale while revalidate case study. That doesn't guarantee the same outcome on every site, but it does prove the pattern can move production metrics at large scale.

SWR won't help first-time visitors with an empty cache, and it won't fix a slow origin by itself. It helps most after the first request has already populated the cache, which is why field data matters more than synthetic tests alone. If you're validating the effect on your own pages, pairing it with real user monitoring gives you the clearest picture of whether repeat views are getting faster.

Best Practices and Common Pitfalls

Start with content change rate, not with a default number copied from another site. A stylesheet that changes once a week can tolerate a longer grace window than a product listing page that updates often. The right max-age and SWR window should match how much staleness your users can accept.

Prefer asynchronous SWR at the edge when the platform supports it, because it avoids making the first visitor after expiry pay the origin penalty. That said, the edge still needs enough capacity to absorb revalidation bursts on popular objects. If many URLs expire together, synchronized refreshes can create a cache stampede, which is why tools like what are internet cookies and cache matter when you're thinking about storage behavior more broadly.

Don't treat the stale window as a guarantee. Treat it as a controlled fallback.

Scenario Do Dont
Versioned static files Use SWR for quick repeat loads Refresh them on every request
Personalized responses Keep them out of shared SWR Assume one cached copy fits all users
Edge deployment Use asynchronous refresh where available Ignore revalidation bursts
Frequently changing content Keep the window short Let stale content linger too long

SWR is strongest for static or slowly changing assets like fonts, build files, and images. It's risky for anything user-specific, because freshness errors become visible fast.

Testing and Monitoring Stale While Revalidate

Start in Chrome DevTools. The Network panel shows cache behavior, the Application tab exposes Cache Storage for service worker caches, and the Disable cache checkbox gives you a clean baseline for comparison. Lighthouse and PageSpeed Insights are still useful for lab signals, but they won't tell you whether repeat visitors are hitting the cache the way you expect.

For production monitoring, it helps to combine lab checks with field data and scheduled scans. A tool like PageSpeed Plus can track LCP, INP, CLS, and TTFB through RUM, run automated hourly or daily scans, test full sites from sitemap URLs, and compare load times across locations. If you're evaluating monitoring vendors too, Monro Cloud tool reviews is a useful outside reference point for how teams compare website monitoring options.

A practical checklist

  • Confirm headers: verify max-age and stale-while-revalidate on the response you expect.
  • Check cache layer: inspect browser cache behavior and service worker storage separately.
  • Compare repeat visits: test with and without cache enabled.
  • Watch real users: look for changes in field metrics after deployment.
  • Keep remediation close: use the included WordPress plugin when you need a direct way to apply caching, JavaScript delay, CSS optimization, and image improvements in one place.

That last point matters because testing without follow-through is where many teams stall. If you want monitoring, remediation, and a WordPress plugin in one workflow, PageSpeed Plus is built for that kind of day-to-day performance work.

Frequently Asked Questions About Stale While Revalidate

Is stale while revalidate safe for logged-in or personalized content? Not usually. Shared caches can serve the wrong user if the response isn't keyed correctly, so user-specific content should stay out of a shared SWR setup unless you've isolated the cache per user.

How does it interact with must-revalidate or no-cache? The response still needs to obey the cache directives that surround it, and SWR only applies within the bounded grace period already described in RFC 5861. If your policy forces revalidation every time, SWR won't override that requirement.

What if the origin is slow or unreachable during background refresh? The cache can still serve stale content during the allowed window, which is the main reason the pattern protects user experience. Once the stale window ends, the cache must stop serving stale responses unless it has additional instructions.

How should I size the stale window? Short windows fit frequently changing assets, longer windows fit resources that change rarely and cost more to regenerate. Start with the content's real update rhythm, then tighten the window if freshness matters more than speed.


If you want a clearer way to monitor how stale while revalidate affects repeat visits, Core Web Vitals, and cache behavior across real traffic, explore PageSpeed Plus. It combines monitoring, scans, and a WordPress plugin so you can see whether your caching strategy is helping users, not just looking good in a header.