Service Workers Overview
SW lifecycle install/activate/fetch, scope, update story, and what belongs in a service worker vs the page.
- browser
- service-worker
- offline
- pwa
- cache
A service worker is an event-driven worker that sits between pages and the network for a given scope. It enables offline shells, push, background sync patterns, and custom caching — and it can also brick deploys if you cache HTML forever incorrectly.
Docs: MDN Service Worker API, web.dev Service workers.
Lifecycle
register → install → waiting → activate → controls clients
↓
fetch / push / sync events
// page
if ('serviceWorker' in navigator) {
await navigator.serviceWorker.register('/sw.js', { scope: '/' });
}
// sw.js
self.addEventListener('install', (event) => {
event.waitUntil(precache());
self.skipWaiting(); // careful: may take over early
});
self.addEventListener('activate', (event) => {
event.waitUntil(cleanupOldCaches().then(() => self.clients.claim()));
});
self.addEventListener('fetch', (event) => {
event.respondWith(handle(event.request));
});
Scope and HTTPS
SW scripts must be served from HTTPS (or localhost), under the path rules for scope. A worker at /app/sw.js can’t control / unless scope allows. Max scope is limited by Service-Worker-Allowed header when needed.
Updates
Browsers re-check sw.js (byte-different) on navigations. New worker installs, then waits until old clients release — unless skipWaiting + clients.claim. UX pattern: prompt “Update available” then registration.waiting.postMessage('SKIP_WAITING').
Fetch strategies
Use Cache API deliberately — Cache Storage API:
- Cache-first for hashed static assets
- Network-first for HTML
- Never cache opaque personalized API responses without keying
What belongs in SW vs page
| SW | Page |
|---|---|
| Offline asset routing | Complex UI state |
| Push event handling | Rendering |
| Precache lists | User gestures |
| Cross-tab coordination (limited) | DOM |
SW has no DOM. Communicate via postMessage / MessageChannel.
Footguns
- Caching
index.htmlwith long TTL → stuck clients. - Forgetting to version caches.
- Intercepting POST accidentally.
- Aggressive
skipWaitingcausing mixed asset versions mid-session. - Assuming SW runs forever — it stops; design restart-safe handlers.
Interview out-loud
“Service workers intercept fetch for a scope after install/activate. I precache fingerprinted assets, network-first HTML, version caches, and use skipWaiting carefully with an update UX. HTTPS-only, no DOM.”
Kill switch
Always keep a way to unregister broken workers (support article + admin flag that serves a no-op SW or Clear-Site-Data: "storage"). A bad cache strategy can brick clients until you ship a fixed worker — plan the recovery path before the incident.
Update UX copy
When a new worker waits, show a non-blocking toast: “Update available — refresh to apply.” On confirm, postMessage skipWaiting and reload. Avoid forced reloads mid-checkout. Test the waiting state by deploying twice quickly and keeping an old tab open — this is where mixed asset versions appear if skipWaiting is automatic.
Related
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
Related guides
- Cache Storage APIPrecache and runtime cache with the Cache API: match, put, strategies, and how it differs from HTTP cache.
- BFCache Back Forward CacheHow the back/forward cache freezes pages for instant history nav, what blocks it, and how to restore state safely.
- Browser DevTools Network PanelRead waterfalls, timing phases, headers, throttling, and initiator chains in the Network panel like a production debugger.
- Browser DevTools Performance PanelRecord main-thread timelines: long tasks, style/layout/paint, frames, and how to turn flame charts into INP fixes.
- Browser Extension Messaging BasicsHow content scripts, background/service workers, and pages talk: runtime messaging, ports, and security boundaries.