Service Workers: the browser superpower you should be using
How Service Workers work, caching strategies, push notifications and background sync. The complete guide to turning your site into a PWA.
Your user opens the app on the subway, the tunnel swallows the signal, and everything breaks. Lost form, vanished data, error screen. Sound familiar? Service Workers exist to solve exactly this kind of problem, and much more.
Service Workers are scripts that run in the background in the browser, intercepting network requests, managing cache and enabling offline functionality. They're the foundation of PWAs, push notifications and background sync. And the best part: they're simpler to implement than they seem.
Mental model: a Service Worker is a programmable concierge standing between your app and the network. Every request walks past it first. It lives in its own room (separate thread), can't touch the DOM, and keeps working even after you leave the building.
What exactly is a Service Worker?
Think of it as a programmable network proxy that lives between your app and the internet:
- Runs on a separate thread (doesn't block the UI)
- Has no access to the DOM (communicates via postMessage)
- Requires HTTPS (except localhost)
- Has its own lifecycle: install, activate, fetch
- Persists between sessions (survives closing the tab)
The impact is real:
- Page TTFB: ~300ms without SW vs ~5ms with cache (60x faster)
- CSS/JS: ~150ms vs ~2ms (75x faster)
- Repeat visits: ~1.5s vs ~100ms (15x faster)
War story: when Twitter rebuilt its mobile web app as Twitter Lite, the team leaned hard on Service Workers and reported a 70% reduction in data consumption, a 20% drop in bounce rate, and 65% more pages per session. Same product, same users, same flaky networks. Just a concierge at the door.
Registration and the lifecycle
In the Service Worker, the complete lifecycle:
Think of install as stocking the pantry, activate as throwing out expired food, and fetch as the concierge answering the door.
The 4 caching strategies you need to know
Cache First for static assets (CSS, JS, images, fonts):
Network First for API calls and dynamic data, falling back to cache when the network sulks. Stale-While-Revalidate is the best of both worlds for feeds and avatars: serve the leftovers, cook a fresh plate in the background. Network Only / Cache Only for auth and payment requests, or for versioned assets you trust completely.
Workbox: the production-ready version
In 2026, Workbox is still the path of least resistance. Pair it with the Vite PWA plugin (or the Next.js / Nuxt equivalents) and you skip 90% of the boilerplate. Just remember Workbox v7+ ships as ESM only, and workbox-cli has been deprecated in favor of bundler integrations.
Pitfalls that will bite you in production
- Cache versioning bugs forget to bump
CACHE_NAMEand users keep getting stale assets forever. Treat the version string like a database migration. - The "stuck SW" an old Service Worker keeps serving old code because a new one is waiting behind it. Users have to close every tab for the new one to activate.
skipWaiting()race conditions calling it naively can swap the SW mid-session, leaving the page talking to a newer SW that expects different asset hashes. Show an "update available" prompt instead of forcing it.- Changing strategies requires unregister if you shipped Cache First and want Network First, old clients still run the old logic until the SW updates. For dramatic changes, plan an unregister path.
- Scope traps a SW at
/app/sw.jsonly controls/app/*. Put it at the root unless you really mean to scope it.
Debugging tips
Open DevTools > Application > Service Workers and keep these checkboxes handy:
- Update on reload forces the SW to re-check on every refresh. Lifesaver during development.
- Bypass for network ignores the SW entirely and hits the network raw, great for isolating "is it the cache lying to me?" bugs.
- Update button manually triggers an update check without reloading.
- Offline toggle (in the Network tab) simulates the subway tunnel.
- Application > Cache Storage lets you inspect exactly what's sitting in each cache bucket.
FAQ
Service Worker vs Web Worker, what's the difference? Web Workers are generic background threads for heavy computation, one per page, die with the tab. Service Workers are specialized network proxies, one per origin/scope, persist across tabs and sessions.
Do I really need HTTPS on localhost?
No. localhost (and 127.0.0.1) is treated as secure by browsers precisely so you can develop without certs. Everywhere else: HTTPS or nothing.
How do I update a Service Worker in production?
Bump the cache version, ship the new sw.js, and the browser fetches it on next navigation (byte-diff check). The new SW installs, waits, and activates when all controlled tabs close. For faster rollout, listen for updatefound in the client and prompt the user to reload.
Can Service Workers read cookies?
Not directly via document.cookie (no DOM, remember?). But cookies still ride along on fetch requests the SW intercepts, and you can read or set them via the Cookie Store API where available.
How do I unregister in an emergency?
Ship a "kill switch" SW that calls self.registration.unregister() and clears every cache with caches.keys().then(keys => keys.forEach(k => caches.delete(k))). Users who load the page once get cleaned up automatically. Always have this file ready before you ship your first SW.
Key Takeaways
Service Workers are probably the most underutilized feature of modern browsers. With just a few lines of code, you transform the user experience: instant repeat visits, app working offline, push notifications. Start with Workbox and a Vite PWA plugin, and you'll get 80% of the benefit with 20% of the effort.