A service worker can make returning visits more resilient and reduce repeated network work, but adding one does not automatically improve Core Web Vitals. The useful question is which requests it should handle, how fresh their responses must be and what happens when a release changes. Start with a narrow set of public assets. Expand only when testing shows a benefit worth the maintenance.
Separate the worker from the cache
A service worker is an event driven script that can intercept requests from pages it controls. Cache Storage is a separate store of request and response pairs. Neither replaces the browser's HTTP cache. A response fetched by the worker can still involve ordinary HTTP caching, so identify which layer supplied it before attributing a faster result to your code.
Cache Storage does not automatically enforce HTTP freshness rules. Your application decides when to store, update and remove its entries. A server header cannot substitute for that policy. If the objective is simply to reuse public stylesheets and images, check the existing browser caching configuration before introducing a programmable layer.
Choose a strategy for each resource
For public assets with content fingerprints in their URLs, checking the cache before the network is a reasonable starting point. The unchanged URL represents unchanged content. That logic does not transfer to account data, availability or HTML that must reflect a deployment.
Trying the network first favors freshness but can leave the visitor waiting on an unreliable connection. Define cancellation, fallback and failure behavior deliberately. Serving a stored response while refreshing it in the background favors quick reuse, but the current visitor may see the older content. It also creates network work even when a cached response is available.
Treat those as product decisions. An offline help page can be useful; an outdated confirmation of a payment is dangerous. Do not apply a universal caching strategy merely because every request passes through the same handler.
Keep the first visit in view
Registration, installation, activation and control are different states. A newly registered worker normally does not control the initial page that registered it. Returning visits may benefit after the worker is ready, while a fresh visitor still depends on the ordinary loading path.
Aggressive precaching can compete with resources the current page needs. Cache only what supports an intentional experience. Improve the server response, resource discovery and rendering path independently. The server response time guide remains relevant even when an already cached visit looks fast.
Start with a deliberately limited example
This illustrative worker precaches an explicit public asset list and serves matching requests from that cache when possible. Place it in a worker script, register it separately in a secure context and replace the asset paths with real files. The listed responses must be public and independent of login state.
const CACHE = "editorialAssetsRelease";
const ASSETS = [
"/assets/site.abc123.css",
"/assets/brand.def456.svg"
];
self.addEventListener("install", event => {
event.waitUntil(
caches.open(CACHE).then(cache => cache.addAll(ASSETS))
);
});
self.addEventListener("fetch", event => {
const request = event.request;
const url = new URL(request.url);
if (request.method !== "GET" ||
url.origin !== self.location.origin ||
!ASSETS.includes(url.pathname + url.search)) return;
event.respondWith((async () => {
let cached;
try {
const cache = await caches.open(CACHE);
cached = await cache.match(request);
} catch {}
return cached || fetch(request);
})());
});Change the cache name and fingerprinted asset URLs together for a release. A failed required precache request can fail installation. This example has no HTML fallback, runtime cache growth or automatic update takeover. Those omissions keep its scope explicit; production integration still needs registration, update handling and retirement of caches owned by this application.
Make updates compatible with open tabs
A newly installed worker can wait while the active worker still serves existing clients. That behavior helps avoid mixing an old page with incompatible new resources. Calling skipWaiting() and clients.claim() changes the lifecycle and control behavior; neither should be added as a general speed optimization.
Choose whether to offer an update prompt, wait for a natural reload or support compatible versions concurrently. Keep earlier fingerprinted assets available while existing pages can still request them. Delete only cache names your application owns, with a retention policy that accounts for active clients. Follow the service worker lifecycle guidance when designing that transition.
Protect private content and handle missing storage
Bypass caching for authentication, account pages and sensitive API responses unless a separately reviewed design requires otherwise. A URL allowlist is easier to reason about than caching every successful request. Never assume that a cookie or a response header makes a broad Cache Storage handler safe.
If the application deliberately stores user specific content, design logout, account switching and deletion together. Also expect eviction and unavailable cached resources. Offline support must explain what remains usable and what requires connectivity; it must not turn missing data into an apparently successful action.
Test states, not just a warm reload
Compare a clean visit, a controlled visit with populated storage, an offline visit and an update with an older tab open. Inspect the worker's scope and controller, the actual Cache Storage entries and the request source. Disabling the HTTP cache in developer tools does not by itself prove that Cache Storage has been bypassed.
Use a trace to investigate slow behavior and field measurements to check visitor outcomes. Good Core Web Vitals boundaries are LCP at or below 2.5 s, INP at or below 200 ms and CLS at or below 0.1, assessed at the 75th percentile with mobile and desktop evaluated separately. A fast local repeat visit is not evidence that the field distribution meets them.
Keep the worker only when its benefit is clear. Correct content, predictable updates and reliable recovery are part of performance engineering, not optional extras after a cache hit. Use the field and lab data guide to keep those observations in their proper context.