Glossary

Service worker

Service worker is a JavaScript worker that sits between a web page and the network, so it can intercept requests, serve cached responses and keep a site usable offline. It is defined by the W3C Service Workers specification and is the core building block of a PWA. Service workers only run in secure contexts: HTTPS, or localhost for local development.

How it works

A page calls navigator.serviceWorker.register() with the URL of a script. The browser downloads it, runs it in a separate worker thread with no access to the DOM, and moves it through a fixed set of states: parsed, installing, installed, activating, activated and redundant. Three events matter most:

  • install: fires once per new script version. Use event.waitUntil() to pre-cache files; the worker is not treated as installed until the promises resolve successfully.
  • activate: fires when the worker takes over. A first-time worker activates immediately, but an updated worker waits until every page controlled by the old version is closed, unless you call skipWaiting().
  • fetch: fires for each request from a controlled page. Call event.respondWith() to answer from a cache, the network, or a mix of both.

A new worker does not control the page that registered it. The page needs a reload, or the worker must call clients.claim().

Scope limits which pages a worker controls. By default the maximum scope is the folder that holds the script, so /js/sw.js can only control /js/ and below. A server can widen this by sending a Service-Worker-Allowed response header on the script.

Updates are byte-based. When the browser checks for an update, it fetches the script again and compares it byte for byte with the installed copy. With the default updateViaCache: 'imports', that script fetch always skips the HTTP cache. A registration is stale once more than 86,400 seconds (24 hours) have passed since its last update check, and from then on imported scripts skip the HTTP cache too.

// sw.js: cache two files on install, answer from cache first
self.addEventListener('install', (event) => {
  event.waitUntil(caches.open('v1').then((c) => c.addAll(['/', '/hello.txt'])));
});
self.addEventListener('fetch', (event) => {
  event.respondWith(caches.match(event.request).then((hit) => hit || fetch(event.request)));
});

Run in headless Chromium against a local server, then reloaded with the server shut down, the page still got a response:

register()      -> scope http://localhost:8765/, isSecureContext true
after reload    -> navigator.serviceWorker.controller is set
fetch /hello.txt (server stopped) -> 200 hello from cache
register('/js/sw.js', {scope: '/'}) -> SecurityError: ... The path of the provided scope ('/') is not under the max scope allowed ('/js/').

Does a service worker need HTTPS?

Yes. Service workers are available only in secure contexts, so the page must be served over HTTPS. Browsers treat localhost as secure, which is why local development works without a certificate. The restriction exists because a worker can rewrite every response for its scope.

Common pitfalls

  • Scope error on register: putting the script in a subfolder and registering a wider scope throws SecurityError ... not under the max scope allowed. Serve the script from the site root or send Service-Worker-Allowed.
  • Old version keeps serving: a new worker waits while any tab uses the old one, so users see stale files after a deploy. Show an update prompt, or call skipWaiting() only when you know it is safe.
  • Cache never expires: caches.open('v1') entries live until you delete them. Name caches by version and delete old ones in the activate handler.
  • Stale imported scripts: with the default updateViaCache: 'imports', files pulled in by importScripts() can come from the HTTP cache until the registration goes stale. Version their URLs.
  • Expecting DOM access: a worker has no DOM access, and synchronous XHR and Web Storage (localStorage) cannot be used. Use the Cache API, and postMessage to talk to pages.

Related terms

  • PWA — a site that combines a service worker with a web app manifest to be installable and work offline.
  • HTTPS — the secure-context requirement for registering a service worker.
  • HTTP — the requests and responses a fetch handler intercepts.
  • DOM — not available inside a service worker.
  • CORS — still applies to cross-origin requests that a fetch handler makes.

See also

  • Term: PWA — the app model that service workers make possible