What is a Service Worker?
A JavaScript file running in the background of a web page, intercepting network requests. Powers offline support, push notifications, faster repeat loads.
What is a service worker?
A service worker is a JavaScript file that runs in the background of a web page, separate from the main browser thread. Its core power is intercepting and modifying network requests made by the page. This single capability unlocks offline support, push notifications, background sync, and dramatically faster repeat-load performance — features that previously required native apps.
Service workers were standardized in 2015 and shipped in Chrome 40, Firefox 44, Safari 11.1 (with delays), and Edge from inception. They're the foundation of Progressive Web Apps (PWAs): web apps that install to the home screen, work offline, and feel native. Even sites that don't aim to be PWAs use service workers for performance — caching expensive responses, pre-loading critical assets, deduplicating API calls.
What service workers can do (and can't)
Service workers run in a special context with strict capabilities and limitations:
Can do:
- Intercept network requests. The
fetchevent fires for every request the page makes — HTML, CSS, JS, images, API calls. The worker decides: serve from cache, modify the request, fetch from network, or fallback if offline. - Cache responses programmatically. Service workers have access to the Cache API — a separate cache storage from the browser HTTP cache, with explicit programmatic control.
- Push notifications. Receive push messages from a server even when the page is closed, then display notifications to the user.
- Background sync. Defer work until the user has connectivity. Queue API calls offline, send when network returns.
- Background fetch. Long-running downloads that continue even after the page closes.
Cannot do:
- Access the DOM directly. Service workers run in a separate context. They communicate with pages via
postMessageonly. - Use synchronous APIs (XHR sync, localStorage). Async-only environment. Use
fetchand IndexedDB instead. - Persist state across restarts arbitrarily. The browser can terminate the worker any time it's idle. Use IndexedDB or Cache for state, not module variables.
- Run on insecure origins. Service workers require HTTPS (except
localhostfor development).
The service worker lifecycle (5 stages)
- Register. Page calls
navigator.serviceWorker.register('/sw.js'). Browser downloads the worker file. - Install. Browser fires the
installevent. Worker typically pre-caches critical assets here. - Activate. Browser fires
activateevent. Worker takes control of pages on next navigation (useclients.claim()to take control immediately). - Run / handle events. Worker handles
fetch,push,sync, etc. as they fire. Browser may terminate the worker between events to save memory. - Update. When the user revisits, browser checks if
sw.jschanged (byte-by-byte). If so, the new version installs but waits for all old-version pages to close before activating. Force-update withskipWaiting().
Common service worker patterns
Cache-first for static assets
For CSS, JS, fonts, images that change infrequently: serve from cache, fall back to network, update cache in the background. Page loads instantly on repeat visits.
Network-first with cache fallback for HTML
For dynamic HTML pages that should be fresh: try network first (with a short timeout), fall back to cache if offline or slow. User sees fresh content when online, cached content when not.
Stale-while-revalidate for API calls
Serve cached API response immediately, then fetch fresh in the background and update cache. User sees instant data with eventual consistency.
Network-only for mutations
POST/PUT/DELETE requests bypass the cache entirely — they must hit the network or queue for background sync.
Offline-first with shell + dynamic content
Pre-cache the app shell (HTML, CSS, JS bundle) on install. Fetch dynamic content from network with cache fallback. Site works fully offline for cached content, gracefully degrades for new content.
Service workers and Core Web Vitals
Service workers can dramatically improve Core Web Vitals on repeat visits — but on first visit, they add small overhead (registering the worker, loading sw.js). Implications:
- LCP improves dramatically on repeat visits. Pre-cached hero images and critical CSS load instantly.
- FCP improves on repeat visits. Pre-cached HTML shell renders before network roundtrip.
- First-visit cost is real. Registering and installing the worker, pre-caching assets, parsing additional JavaScript — all add cost on the first session. Don't over-engineer.
- CLS unaffected. Service workers don't impact layout stability either way.
- INP can improve. Pre-cached interactive responses (e.g. cached search suggestions) reduce server-roundtrip latency on user interactions.
Service workers vs other caching layers
Modern web apps have multiple caching layers. Service workers sit at a specific spot:
- Browser HTTP cache: Implicit, controlled by Cache-Control headers. Browser decides what to cache and when. No JavaScript control.
- Service Worker Cache API: Explicit, controlled by JS. Survives page reloads. Programmatic control over what to cache and serve.
- CDN cache: Edge servers. Fast but shared across all users. Updates via cache invalidation.
- HTTP/2 push (deprecated): Server pushes resources. Removed from Chrome in 2022 because it didn't outperform service workers.
FAQ: Service Workers
Do I need a service worker for my site?
If your site is content-heavy and users return often, yes — repeat-visit performance gains are large. If users visit once and never come back, the first-visit overhead may not pay off. Pure marketing sites with low return rates don't necessarily benefit.
What's the difference between a service worker and a web worker?
Both run in background threads. Web workers handle CPU-bound work in parallel with the main thread (image processing, computation). Service workers specifically intercept network requests and persist across page loads. Different APIs, different lifecycles.
Why do service worker updates take so long to deploy?
By default, a new worker version installs but waits for ALL pages running the old version to close before activating. For users with the site open in a tab forever, this can be days. Force-update with skipWaiting() in the install handler — but be careful, can cause assets and code to mismatch mid-session.
How do I debug a service worker?
Chrome DevTools → Application → Service Workers shows registered workers, current state, errors. Network tab shows which requests were served from the SW cache (look for the small gear icon). Lighthouse audits include PWA / service worker checks.
Do service workers work in Safari?
Yes, since iOS 11.3 / Safari 11.1. Implementation has been weaker historically (background sync delayed, push notifications limited until iOS 16.4). Always test PWA features on real Safari, not just Chrome.
Can a service worker break my site?
Yes, easily. A buggy worker that always returns cached responses (even stale ones) creates a permanently-broken UX that's hard to recover from — users won't see fixes until the worker self-updates. Always include a kill switch: a check that disables the worker on a flag your server controls.
How LoadFocus measures service worker impact
LoadFocus runs Lighthouse-based page speed tests from real Chrome instances in 25+ regions, capturing first-visit and repeat-visit metrics separately. Service worker effectiveness shows up as a large gap between cold-load and warm-load LCP. Schedule audits to validate the worker is actually working in production — broken service worker registrations are a silent killer that doesn't surface in single-page Lighthouse runs.
Related LoadFocus Tools
Put this concept into practice with LoadFocus — the same platform that powers everything you just read about.