Your site already ships content-hashed assets with year-long caching behind a CDN, and repeat visits measure fast. A teammate proposes adding a service-worker cache to make it faster still. Where is the real headroom, and what does owning that cache cost you?
answer
- measure the gap, not the total
- hashed assets already read from local disk
- the document round trip is the headroom
- opaque cross-origin responses hide failures
- a cache no server can purge
basics
~20 sAlmost none of the headroom is in the static assets — those already come off local disk on a repeat visit. What is left is the document request, third-party resources whose headers you do not control, and flaky or absent networks. Against that, weigh a duplicated copy of the bytes, permanent ownership of client-side code, and a cache no server can purge.
solid answer
~60 sStart by asking where the remaining milliseconds actually are. Hashed JS and CSS with a long immutable lifetime already resolve to a local read, so putting the same bytes in a service-worker cache buys nothing on a warm repeat visit. The genuine headroom is elsewhere: the HTML document, which must stay short-lived because it names the hashed assets and therefore costs a network round trip on every visit; resources from origins whose headers you cannot set; and any situation where the network is slow, intermittent or gone. A worker can paint a stored shell immediately and reconcile afterwards, which HTTP caching cannot do for a document you refuse to make stale. The cost side is real: a second copy of the bytes inside a storage quota the browser may evict, code on the request path of every page, a new question in every bug report — "was this served by the worker?" — and a cache you cannot purge from the origin. If offline is not a requirement and the document is already fast, the honest answer is not to ship it.
go deeper
Know that a warm repeat visit already reads hashed assets locally, so re-caching them wins nothing, and that the honest gains are offline support and the HTML request.
Explain why the document must stay short-lived and therefore costs a round trip every visit, and name the costs: duplicated bytes under a quota, opaque cross-origin responses, and code on every request path.
Demonstrate that you would gate the decision on field data and a stated product requirement, define success before rollout, and be willing to remove the worker if the controlled cohort shows no gain.
Own the total-cost-of-ownership argument — support burden, on-call implications and the fact that this cache cannot be purged from your side — and set the standard for when a team may take it on.
## Measure the gap, not the total The mistake in the proposal is arithmetic. "Repeat visits are fast" is the baseline; a service worker has to beat that baseline, not beat a cold visit. So the first move is to work out what a warm repeat visit still spends time on. On a site with content-hashed filenames and a long immutable lifetime, a warm repeat visit reads the JS and CSS from the browser's own store without touching the network. There is no round trip left to remove. Serving those same bytes through a service-worker cache is a local read either way, plus a little extra work to start the worker and run your handler. Any pitch that boils down to "cache the bundles again" has no headroom in it. ## Where the headroom actually is **The document.** HTML is the one thing you cannot cache aggressively, because it names the hashed assets — cache it hard and users are pinned to an old build. So every visit, warm or cold, pays a network round trip for the document before anything can start. That round trip is the largest remaining cost on a repeat visit, and it is exactly the thing headers cannot remove and code can: a worker can answer the navigation from a stored shell and reconcile with the network behind it. This is the strongest performance case for a service worker on an otherwise well-tuned site, and on a slow connection it can be the difference between a blank second and an instant paint. **Resources you do not control.** Fonts, images or scripts from another origin arrive with whatever lifetime that origin chose. A worker can hold onto them. Be careful here: cross-origin responses fetched without CORS come back opaque — your code cannot read their status or body, so a failed or error response can be stored as if it were fine, and it occupies far more quota than its real size. Cache third-party resources deliberately and narrowly, if at all. **Bad networks.** Everything above assumes the network works. Field data on real users normally shows a long tail where it does not. If your product is used on the move, in warehouses, on hotel Wi-Fi, resilience is a feature and the HTTP cache cannot deliver it. ## The bill you are agreeing to pay - **Duplicate bytes under a quota.** Whatever the worker stores sits in origin storage alongside whatever the HTTP cache already kept. The browser may evict the lot under pressure or after long disuse, so the cache is a fast path, never a guarantee. - **Code on the critical path forever.** The worker sits in front of every request in its scope. A bug there is not a slow page; it is a broken site, and the broken code is on the user's device. - **A permanently harder debugging story.** "Can you reproduce it?" now depends on which build's worker that user carries and what is in their cache. Support and QA both get more expensive. - **A cache with no purge button.** You can invalidate a CDN or change a header and know that clients converge. Nothing you do on the server empties a cache on someone's laptop; only code you manage to deliver to that device can. - **Ownership.** Someone must own the worker, review changes to it, and keep testing it after the person who wrote it moves on. ## How to decide, and how to check afterwards Write the decision down as a requirement, not a preference. Ship it if offline or degraded-network use is something the product promises, or if instant navigation is a target you have measured and cannot hit any other way — for instance the document round trip dominates your field numbers on the slowest quartile of users. Do not ship it because caching is generally good. If you do ship it, define success before the rollout and check field data afterwards, comparing sessions that had a controlling worker against sessions that did not. A change that costs this much ownership should be able to show its win in real-user numbers; if it cannot, remove it. A service-worker cache you cannot justify is not a neutral extra — it is a permanent liability sitting in front of every request your users make.
- How would you show, after the rollout, that the service worker actually helped?Compare field data from sessions controlled by the worker against sessions that were not, on the same metrics and the same percentiles — not a lab run on your laptop. Report the worker's build alongside the beacon so you can also tell which version a session had. If the controlled cohort does not move, you have paid the ownership cost for nothing.
- Why be cautious about caching third-party resources in a service worker?Responses fetched cross-origin without CORS are opaque: your code cannot see the status or the body, so an error page can be stored as though it were the asset, and it consumes far more quota than its real size. If you cache them at all, keep the list short, explicit, and refreshed on a schedule you chose.
- Does a service worker help a site whose visitors mostly arrive once from search?Barely. The worker cannot touch the visit that installs it, so a population dominated by first-time visitors sees almost none of the benefit while you carry all of the cost. That traffic shape is better served by CDN reach, smaller payloads and a fast document.
saying these in an interview costs you the question
- Assumes caching the same bundles again makes repeat visits faster
- Ignores that the first visit is entirely unaffected
- Forgets the stored copy competes for an evictable storage quota
- Caches opaque cross-origin responses without noticing failures get stored
- Treats it as a one-off change rather than permanent ownership