# Service workers: what they are, and a minimal one

> The programmable network proxy behind offline PWAs — a minimal registration, the lifecycle in one pass, the traps, and where each part is documented.

import { CardGrid, LinkCard } from '@astrojs/starlight/components';

A **service worker** is a script the browser runs in its own worker thread, separate
from any page, which can intercept network requests from the pages it controls and
answer them itself. That is what makes offline support, instant repeat loads, and
push possible: the worker keeps running after the tab is gone.

It has no DOM access, and it only runs in a secure context (HTTPS, or `localhost`
during development).

## The smallest one that works

Register it from the page:

```js
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
} else {
  // No service worker: the site still works, it just has no offline layer.
}
```

And in `/sw.js`, answer requests from a cache, falling back to the network:

```js
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((hit) => hit || fetch(event.request)),
  );
});
```

That is a complete, working service worker. Everything else — precaching, update
strategy, expiry — is refinement on top of these two pieces.

## The lifecycle, in one pass

A registered worker is **installed**, then **activated**, and only then does it start
controlling pages. A page loaded before the worker activated stays uncontrolled until
it is reloaded. When you ship a new `sw.js`, the browser installs it alongside the old
one and leaves it **waiting** until the old worker releases its clients — which is why
a deploy does not take effect on the very next reload unless you ask it to.

See [Service worker lifecycle](/reference/service-worker/lifecycle/) and
[The update flow and skipWaiting](/reference/service-worker/update-skipwaiting/).

## Where it commonly goes wrong

- **Scope** — a worker at `/js/sw.js` controls only `/js/`. Serve it from the root, or
  send `Service-Worker-Allowed`. See [Registration and scope](/reference/service-worker/registration-scope/).
- **Stale users after a deploy** — the new worker sits waiting behind the old one.
- **Caching everything reflexively** — a cache-first strategy on HTML strands users on
  an old page. Choose per request type: [Caching strategies](/reference/service-worker/caching-strategies/).
- **Debugging it like page code** — it has its own lifecycle and its own DevTools pane.
  See [Debugging service workers](/reference/service-worker/debugging/).

## Every topic in this section

<CardGrid>
	<LinkCard title="Service worker lifecycle" href="/reference/service-worker/lifecycle/" description="register, install, activate, the waiting worker, skipWaiting, clients.claim, and updates." />
	<LinkCard title="Registration and scope" href="/reference/service-worker/registration-scope/" description="navigator.serviceWorker.register(), scope rules, Service-Worker-Allowed, and updateViaCache." />
	<LinkCard title="The update flow and skipWaiting" href="/reference/service-worker/update-skipwaiting/" description="How the browser detects new versions, the waiting state, skipWaiting(), and clients.claim()." />
	<LinkCard title="The fetch event and routing" href="/reference/service-worker/fetch-event/" description="FetchEvent, event.respondWith(), routing by destination or URL, and passthrough." />
	<LinkCard title="Caching strategies" href="/reference/service-worker/caching-strategies/" description="Cache First, Network First, Stale-While-Revalidate, Network Only, Cache Only — when to use each." />
	<LinkCard title="The Cache API" href="/reference/service-worker/cache-api/" description="caches.open(), cache.add(), cache.match(), expiration, and opaque responses." />
	<LinkCard title="The Clients API" href="/reference/service-worker/clients-api/" description="Reaching the pages a worker controls — matchAll, claim, and focusing or opening a window." />
	<LinkCard title="Navigation preload" href="/reference/service-worker/navigation-preload/" description="Starting the navigation request in parallel with worker startup so boot time is not on the critical path." />
	<LinkCard title="Offline fallback" href="/reference/service-worker/offline-fallback/" description="Pre-caching a fallback page and serving it when both cache and network fail." />
	<LinkCard title="Background Fetch" href="/reference/service-worker/background-fetch/" description="Handing long downloads to the browser so they survive the page being closed." />
	<LinkCard title="Periodic Background Sync" href="/reference/service-worker/periodic-background-sync/" description="Refreshing content on a browser-decided schedule, and the narrow support it has." />
	<LinkCard title="Workbox" href="/reference/service-worker/workbox/" description="Routing, precaching, expiration, background sync, and workbox-window for update UX." />
	<LinkCard title="Debugging service workers" href="/reference/service-worker/debugging/" description="Chrome DevTools, Firefox, and Safari tooling for inspecting state, caches, and update flow." />
	<LinkCard title="Background sync: retrying failed requests" href="/reference/service-worker/background-sync/" description="How the Background Sync API defers a failed request until the device regains connectivity, its registration/event API, and execution-time limits." />
</CardGrid>

## Where to go next

- [Web app manifest](/reference/manifest/) — the other half of an installable app.
- [Install prompt](/reference/installation/install-prompt/) — what browsers require before offering installation.

← Back to the [Reference](/reference/) overview.