# Service worker startup and fetch overhead

> How a stopped service worker delays fetch handling, how to measure its navigation timing, and when preload or removing a no-op handler avoids the cost.

A stopped service worker must start before it can run a `fetch` handler. When that handler then goes to the network, startup and handler execution precede the network request; navigation preload can start the navigation request in parallel with worker startup ([Service worker deployment](https://developer.chrome.com/docs/workbox/service-worker-deployment), Chrome for Developers).

BCD records `NavigationPreloadManager`, the mitigation used on this page, from Chrome 59, Edge 18, Firefox 99, and Safari 15.4 ([NavigationPreloadManager.json](https://raw.githubusercontent.com/mdn/browser-compat-data/main/api/NavigationPreloadManager.json), MDN browser-compat-data).

## How it works

Browsers stop service worker processes when they are inactive and start them when an event needs dispatch. A controlled navigation that reaches a `fetch` handler therefore waits for a stopped worker to start. A cache response can compensate for that cost; a pass-through handler that calls `fetch(event.request)` adds the worker path before the network work it still needs ([Service worker deployment](https://developer.chrome.com/docs/workbox/service-worker-deployment), Chrome for Developers).

Navigation Timing exposes `workerStart`, the point when the request begins to be handled by the worker. It is `0` when no service worker controls the page. Chrome DevTools labels the corresponding request phases `ServiceWorker Preparation` and `Request to ServiceWorker` in the Network panel's Timing tab ([Network features reference](https://developer.chrome.com/docs/devtools/network/reference), Chrome for Developers).

Navigation preload applies to navigation requests. Once enabled on a registration, the browser can start the network request while the worker boots, and the handler reads that response through `event.preloadResponse`. It does not remove the execution cost of other handler logic and can waste a request when the handler responds from cache.

:::caution
Chrome 115 introduced an optimization that omits worker startup and event dispatch when Chromium recognizes that all `fetch` listeners are no-ops. A pass-through listener that calls `fetch(event.request)` is not a no-op and still uses the worker path described above. Remove a listener that provides no response logic instead of relying on this Chromium optimization ([Skip service worker no-op fetch handler](https://chromestatus.com/feature/5136946693668864), Chrome Status).
:::

:::observed
From Chrome 112, Chromium emits the exact console warning `Fetch event handler is recognized as no-op. No-op fetch handler may bring overhead during navigation. Consider removing the handler if possible.` Its DevTools test and message definition are recorded in the cited [Chromium change](https://chromium.googlesource.com/chromium/src/+/b21c192cac10afc37b36d92446a6bdc441f35893) (chromium.googlesource.com), and the version is recorded by [Chrome Status](https://chromestatus.com/feature/5136946693668864).
:::

## Examples

Measure startup on the page, then use preload only for network-backed navigations.

### Measuring the controlled navigation

The fallback branch reports that this navigation has no service worker timing rather than subtracting the zero sentinel.

```js
const [navigation] = performance.getEntriesByType('navigation');

if (!navigation || navigation.workerStart === 0) {
  console.log('This navigation has no service worker timing.');
} else {
  const beforeWorker = navigation.workerStart - navigation.startTime;
  const workerToRequest = navigation.requestStart - navigation.workerStart;
  console.table({ beforeWorker, workerToRequest });
}
```

Collect these fields on real devices. The deployment guidance says startup varies with device capability and CPU pressure, so a single development-machine value is not a general budget.

### Overlapping startup with a navigation request

Enable preload during activation when the registration exposes it. The fetch handler uses the preloaded response and falls back to an ordinary fetch when preload is absent or produces no response.

```js
self.addEventListener('activate', (event) => {
  if (!('navigationPreload' in self.registration)) return;
  event.waitUntil(self.registration.navigationPreload.enable());
});

self.addEventListener('fetch', (event) => {
  if (event.request.mode !== 'navigate') return;

  event.respondWith((async () => {
    const preloaded = await event.preloadResponse;
    if (preloaded) return preloaded;
    return fetch(event.request);
  })());
});
```

If navigations normally come from Cache Storage, compare the avoided network time with the unused preload request before enabling it.

## Correction (2026-10-23)

Chrome 112 introduced the console warning for recognized no-op `fetch` handlers. The optimization that omits worker startup and event dispatch shipped in Chrome 115. The BCD support statement now describes `NavigationPreloadManager`, which is the API represented by the cited data file ([Skip service worker no-op fetch handler](https://chromestatus.com/feature/5136946693668864), Chrome Status; [NavigationPreloadManager.json](https://raw.githubusercontent.com/mdn/browser-compat-data/main/api/NavigationPreloadManager.json), MDN browser-compat-data).

## See also

- [Navigation preload and service worker boot time](/reference/performance/navigation-preload/)
- [Service Worker Static Routing API](/reference/service-worker/static-routing/)
- [Caching strategies for service workers](/reference/service-worker/caching-strategies/)
- [Speed up service worker with navigation preloads](https://web.dev/blog/navigation-preload) (web.dev)
- [Network features reference](https://developer.chrome.com/docs/devtools/network/reference) (Chrome for Developers)