A Service Worker Is a Cache You Cannot Clear From the Server
Adding offline support puts a programmable proxy on your users' devices. It is the only part of your deployment you cannot roll back, so the update path matters more than the feature.

A Service Worker Is a Cache You Cannot Clear From the Server 📴
Adding a service worker is presented as a small enhancement: offline fallback, faster repeat visits, an install prompt. Mechanically it is small. Operationally it is the most consequential thing you can put in a web app, because it is the only piece of your deployment that lives on the user's device and that you cannot reach.
Ship a broken one and every affected visitor keeps getting the broken version. There is no cache purge, no CDN invalidation, no rollback. The only fix is a new service worker that the old one allows to install — which means the update mechanism has to work even when everything else you shipped does not.
Design the update path before the offline behavior
Two rules that make this safe.
Never cache the service worker script itself for long. It should be served with a short or zero max-age. Browsers have protections here, but the config is yours and a long-lived cache header on that one file is the difference between "fix ships in an hour" and "fix ships when the cache expires."
Make new versions take over promptly, on purpose. By default a new worker waits until every tab controlled by the old one closes — which, for a pinned tab, can be days. Explicitly skipping the wait and claiming existing clients means a fix propagates on the next load rather than eventually.
That choice has a real tradeoff: an in-flight session can suddenly be served assets from a different build. Which is why the third rule matters:
Version your caches and clean up on activate. Include a build identifier in the cache name, and on activation delete every cache that is not the current one. Without this, stale entries from three deploys ago survive indefinitely and produce the worst bug class here — a page assembled from mismatched versions, where the HTML expects one asset hash and the cache serves another.
What to cache, and what never to
The safe default is narrow. Cache your own static build output — hashed assets, fonts, an offline page. That is it, until you have a specific reason for more.
Never cache, without deliberate design:
- Authenticated responses. A cached response served to a different user on a shared device is the failure mode, and it is not hypothetical.
- Anything with a
Set-Cookieor that varies by session. - API responses, unless you have decided precisely what stale means for that endpoint and what happens when the user acts on stale data.
- HTML navigations, unless you genuinely want offline navigation and have thought through serving a page whose referenced assets may no longer exist.
For a documentation or marketing site, static assets plus an offline fallback page delivers nearly all the benefit with nearly none of the risk.
The offline page is a real design problem
Most offline pages say "you are offline" and nothing else, which the user already knew.
Better: say what is still available. If cached documentation pages exist, link them. If a draft was in progress, confirm it is saved locally and will sync. If there is nothing, say the page will load when the connection returns, and retry automatically rather than demanding a manual refresh.
The offline page is the one screen guaranteed to be seen at the user's worst moment. It deserves more than a shrug.
Test the update, not the install
Installing a service worker is easy to verify. Updating one is where the failures are, and it needs a deliberate rehearsal:
- Load the site, confirm the worker is active.
- Deploy a change.
- Reload without clearing storage — the way a real user arrives.
- Confirm the new version is in control and old caches are gone.
Then rehearse the emergency: ship a worker that unregisters itself and clears all caches, and confirm a device running the previous version recovers to a clean state. Write that escape hatch before you need it. Producing it under pressure, for users who are already stuck on a broken version, is not a position you want to be in.
Whether to add one at all
The honest test is whether offline use is a real scenario for your users. For a documentation site read on transit, or a tool used in the field, yes. For a marketing page, the performance gain rarely justifies putting an unrollbackable component on every visitor's device.
The feature is small. The commitment is not — and the commitment, not the feature, is what you are actually deciding on.