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 fetch event 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 postMessage only.
  • Use synchronous APIs (XHR sync, localStorage). Async-only environment. Use fetch and 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 localhost for development).

The service worker lifecycle (5 stages)

  1. Register. Page calls navigator.serviceWorker.register('/sw.js'). Browser downloads the worker file.
  2. Install. Browser fires the install event. Worker typically pre-caches critical assets here.
  3. Activate. Browser fires activate event. Worker takes control of pages on next navigation (use clients.claim() to take control immediately).
  4. Run / handle events. Worker handles fetch, push, sync, etc. as they fire. Browser may terminate the worker between events to save memory.
  5. Update. When the user revisits, browser checks if sw.js changed (byte-by-byte). If so, the new version installs but waits for all old-version pages to close before activating. Force-update with skipWaiting().

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.

How fast is your website?

Elevate its speed and SEO seamlessly with our Free Speed Test.

Free Website Speed Test

Analyze your website's load speed and improve its performance with our free page speed checker.

×