# Update strategies

> Choose how your service worker rolls out a new version — immediate takeover, a user-prompted reload, or the quiet default — and when periodic update checks matter.

**Outcome:** a considered choice for how a new service worker version reaches your
users, instead of an accidental default. The mechanism (`skipWaiting()`,
`clients.claim()`, the waiting state) is covered in the
[update flow reference](/reference/service-worker/update-skipwaiting/); this guide is
about which strategy to pick and why.

## The default: consistency

Without calling `skipWaiting()`, a newly installed worker sits in the *waiting* state
until every tab controlled by the old worker closes. The default favors consistency: a
page that loaded without a service worker won't suddenly get one mid-session, and a page
loaded under one worker version won't be handed to a different version's cache
assumptions. For most apps, this quiet default is the right choice — but a reload alone isn't
guaranteed to apply the update: during a reload, the old and new page's clients can
briefly overlap even with a single tab, so the waiting worker only takes over once every
tab controlled by the old worker has actually closed or navigated away.

## Immediate takeover with `skipWaiting()`

Calling `self.skipWaiting()` in the `install` event causes the new worker to kick out
the current active worker and activate itself as soon as it enters the waiting phase,
even while it's still controlling open tabs. It's common to call it directly in the
install handler:

```js
self.addEventListener('install', (event) => {
  self.skipWaiting();
});
```

The trade-off: your new service worker is then likely controlling pages that were
loaded with an older version, which can break things if the new worker's cached
resources are incompatible with the HTML already on the page. The guidance is direct —
if this might break things, don't use `skipWaiting()` unconditionally.

`clients.claim()` is a related, separate decision: it lets a newly activated worker
adopt pages that were already open when it was registered. It only really matters on
the very first load, since a page usually works fine without a service worker for that
first visit thanks to progressive enhancement — so treat it as situational rather than
routine boilerplate.

## Prompting the user before reloading

A middle ground defers `skipWaiting()` to a user-driven moment instead of calling it
unconditionally in `install`: the new worker installs and waits, the page shows the
user an "update available" notice, and only on user action does the page `postMessage()`
the waiting worker to trigger `skipWaiting()`, followed by a controlled reload.

```js
// In the page: listen for a controller change and reload once, after the user
// has agreed to update.
let refreshing = false;
navigator.serviceWorker.addEventListener('controllerchange', () => {
  if (refreshing) return;
  refreshing = true;
  window.location.reload();
});
```

This pattern — covered in full in the
[update flow reference](/reference/service-worker/update-skipwaiting/) — avoids both the
silent inconsistency risk of unconditional `skipWaiting()` and the "update never applies
until the user closes every tab" cost of the pure default.

## Periodic update checks

The browser checks for a new worker script automatically on navigation to an in-scope
page, and on functional events like `push` and `sync` (unless a check already happened
within the previous 24 hours). If you expect a user to keep a tab open for a long time
without navigating or reloading, you may want to call `registration.update()` on an
interval, such as hourly, so a long-lived session still discovers new versions in a
reasonable time:

```js
navigator.serviceWorker.register('/sw.js').then((reg) => {
  setInterval(() => reg.update(), 60 * 60 * 1000);
});
```

## Choosing a strategy

| Situation | Recommended strategy |
|---|---|
| Typical app; users eventually close or navigate away from all tabs | Default (no `skipWaiting()`) — simplest, most consistent. |
| Users keep tabs open for hours/days | Default plus a periodic `registration.update()` check, so updates are discovered even without a fresh navigation. |
| Update carries a breaking cache/schema change | Default, or the user-prompted reload — never unconditional `skipWaiting()`, since it can control old pages with incompatible assumptions. |
| Non-breaking fix that should apply ASAP and disruption is acceptable | Unconditional `skipWaiting()` in `install`. |

## Where to go next

- [The service worker update flow and skipWaiting](/reference/service-worker/update-skipwaiting/) — the underlying mechanism this guide chooses between.
- [Offline strategies](/guides/offline/) — caching strategy overlaps with update strategy for perceived freshness.
- [Service worker lifecycle](/reference/service-worker/lifecycle/) — install/activate/waiting in full.

← Back to the [Guides](/guides/) overview.