v149 · Web APIs · Service Worker Integration

Service Worker Integration

Using Request.isReloadNavigation in a service worker to implement a bypass-cache-on-reload strategy — the same behaviour browsers apply to HTTP caches when the user presses reload.

When a user presses reload, browsers send a conditional request to the network for the main document even if it's in the HTTP cache. Service workers previously couldn't detect this and would often serve stale cached content on reload. isReloadNavigation closes this gap.

navigation strategies

Normal navigation (isReloadNavigation: false)

  • 1. Fetch event fires
  • 2. isReloadNavigationfalse
  • Check cache first
  • Cache hit: serve cached response immediately
  • Cache miss: fetch from network, cache result

Reload (isReloadNavigation: true)

  • 1. Fetch event fires
  • 2. isReloadNavigationtrue
  • Skip cache, go to network
  • Network success: serve fresh, update cache
  • Network failure: fall back to cached response

comparison with alternatives

Signal Available in SW? Detects reload? Notes
request.isReloadNavigation Yes (Chrome 149+) Yes Direct signal — purpose-built for this
Cache-Control: no-cache on reload No No — headers not exposed to SW Browser sends this but SW can't see request headers that indicate reload
PerformanceNavigationTiming.type No Yes (in page only) Only available in page context, not service worker
request.headers.get('Cache-Control') Yes Partial Browser adds max-age=0 on reload but this is unreliable

complete service worker implementation

// sw.js — network-first-on-reload strategy

const CACHE_NAME = 'pages-v1';

self.addEventListener('fetch', event => {
  const req = event.request;

  // Only handle navigation requests
  if (req.mode !== 'navigate') return;

  event.respondWith(handleNavigation(req));
});

async function handleNavigation(req) {
  // Chrome 149+: true when user explicitly reloaded
  if (req.isReloadNavigation) {
    return networkFirstWithFallback(req);
  }
  return cacheFirstWithNetwork(req);
}

async function networkFirstWithFallback(req) {
  try {
    const response = await fetch(req);
    // Update cache with fresh response
    const cache = await caches.open(CACHE_NAME);
    cache.put(req, response.clone());
    return response;
  } catch {
    // Offline: fall back to cache
    const cached = await caches.match(req);
    if (cached) return cached;
    throw new Error('Network unavailable and no cache available');
  }
}

async function cacheFirstWithNetwork(req) {
  const cached = await caches.match(req);
  if (cached) return cached;

  const response = await fetch(req);
  const cache = await caches.open(CACHE_NAME);
  cache.put(req, response.clone());
  return response;
}

see also

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗