Navigation preload as a performance fix: starting the network request while the service worker boots
In one line: Without navigation preload, a service worker’s boot-up time sits in front of a navigation’s network request; per web.dev, enabling preload lets the browser start the network request while the service worker is booting up instead, so the boot-up time no longer blocks the network request.
Where the delay comes from
Section titled “Where the delay comes from”For a page controlled by a service worker that has a fetch event handler, the browser
must dispatch that event to the worker and wait for the response — which means booting the
worker first if it is not already running.
Per web.dev, that boot-up time is device- and condition-dependent: commonly around 50ms on
desktop, more like 250ms on mobile, and it can exceed 500ms on a slow or CPU-throttled
device. Without navigation preload, the network request for the navigation does not start
until after the worker has booted and begun executing the fetch handler — so boot time is
added directly onto the time it takes to get a response.
The TTFB connection
Section titled “The TTFB connection”Time to First Byte includes the time the browser spends checking any active service worker for a matching response before the response arrives. When that check requires a cold boot, the boot delay becomes part of TTFB. Per web.dev, navigation preload starts the network request while the service worker is booting up; the startup delay is still there, but it doesn’t block the network request.
Enabling it and using the result
Section titled “Enabling it and using the result”addEventListener('activate', (event) => { event.waitUntil( (async () => { if ('navigationPreload' in self.registration) { await self.registration.navigationPreload.enable(); } else { // Unsupported: nothing to enable. The fetch handler below still // works, it just waits for the worker to finish booting before the // navigation request starts, same as it would without this file. return; } })(), );});
addEventListener('fetch', (event) => { event.respondWith( (async () => { const preload = await event.preloadResponse; if (preload) return preload; return fetch(event.request); })(), );});'navigationPreload' in self.registration is the feature-detection check; event.preloadResponse resolves to undefined
when preload did not run for that request (for example, non-GET or non-navigation
requests), so the handler must always fall back to a normal fetch(). MDN’s own
FetchEvent.preloadResponse example keeps a started-but-unused preload request alive with
event.waitUntil(preloadResponsePromise.catch(() => undefined)), so it isn’t cancelled if
the handler ends up serving from cache instead.
Where it is supported
Section titled “Where it is supported”NavigationPreloadManager requires a secure context (HTTPS) and is Baseline widely
available, per MDN, since April 2022.
When it doesn’t help
Section titled “When it doesn’t help”Navigation preload is not universally beneficial. Per web.dev, if a page is served straight from the Cache Storage API, the service worker’s boot-up time isn’t a significant problem, because the cached response is already available without waiting on the network — so the delay preload exists to hide is not the bottleneck for that response in the first place.
Practical checklist
Section titled “Practical checklist”- Measure whether your navigation responses come from the cache or the network before adopting preload — a fully precached app shell gets less benefit from it.
- Enable it in
activate, guarded byif ('navigationPreload' in self.registration). - Always await
event.preloadResponseand fall back tofetch()when it resolves toundefined. - Keep a started-but-unused preload request alive with
event.waitUntil(), per MDN’sFetchEvent.preloadResponseexample, so it isn’t cancelled if you end up serving from cache instead. - Set
Vary: Service-Worker-Navigation-Preloadon the server if the preload and normal responses can differ, so caching doesn’t mix them up.
Where to go next
Section titled “Where to go next”- Navigation preload (service worker API reference) —
the full
NavigationPreloadManagerAPI this entry frames as a performance fix. - Core Web Vitals — where TTFB, which navigation preload targets directly, fits into the broader set of page-load metrics.