Skip to the content.

Progressive web apps: the service worker is the whole trick

Progressive web apps: the service worker is the whole trick

A progressive web app is a website that behaves like an installed app — it works offline, it can be added to the home screen, and it loads instantly on repeat visits. That sounds like a big pile of technology, and almost all of it comes from one piece: a service worker, a script the browser runs in the background, sitting between your page and the network. It can intercept every request your app makes and decide whether to answer from a cache, from the network, or from a mix — which is what makes offline and instant loads possible. Understand the service worker and you understand what a PWA actually is; the manifest and the install prompt are trimmings on top.

A service worker intercepts requests and answers from cache or network The page makes a request; the service worker intercepts it and either serves a cached response instantly or falls through to the network, updating the cache. page fetch service workerintercepts every request cache hit → instant miss → network cache network
Every request passes through the service worker, which can answer from cache (instant, offline-capable) or fall through to the network — the interception is the whole mechanism.

Register it, then intercept fetches

A service worker is registered once, installs, and from then on the browser routes the page’s requests through its fetch handler. That handler is where offline and speed come from — you decide what each request returns:

// page: register the worker once
navigator.serviceWorker.register("/sw.js");

// sw.js: intercept requests — serve cache first, fall back to network
self.addEventListener("fetch", (e) => {
  e.respondWith(
    caches.match(e.request).then((hit) => hit || fetch(e.request))  // cache, else network
  );
});

That single handler is what makes the app load with no network — if the response is cached, the request never touches the wire.

Strategy per request type

“Cache first” is not right for everything, and the power of the service worker is choosing a strategy per resource. The app shell (rarely changes) is cache-first; API data (must be fresh) is network-first with a cache fallback for offline; images are cache-first with a size cap:

// pick a strategy by request type — not one policy for everything
if (isShell(e.request))   e.respondWith(caches.match(e.request));                  // cache-first
else if (isApi(e.request)) e.respondWith(fetch(e.request).catch(() => caches.match(e.request))); // network-first, offline fallback

This per-type control is exactly what a plain HTTP cache cannot give you, and it is why the service worker, not the manifest, is the heart of a PWA.

The manifest and the honest caveats

The other PWA pieces are lightweight by comparison. A web app manifest (a JSON file with the app’s name, icons, and theme) is what enables “add to home screen” and a standalone, app-like window — real, but small next to the service worker. And two caveats keep you honest: a service worker requires HTTPS (it can rewrite responses, so the browser demands a secure origin), and cache versioning is a real hazard — because the worker caches aggressively, a deploy can be masked by a stale cache unless you version the cache name and clean up old ones on activation. Get the service worker’s interception and per-type strategies right, add a manifest, mind the cache versioning, and an ordinary website becomes installable, offline-capable, and instant on return — all from that one script in the middle. The offline-first-list and cache-headers exercises build the caching decisions the service worker depends on.