TechWeb Magazine illustration of old and new browser versions passing through a controlled service worker handoff with separate cache shelves and a rollback route
A safe update keeps the old page, new worker and versioned caches compatible until the handoff is complete.

Your server rollback can finish in seconds. A returning browser may still have an older service worker and cached app shell.

That is not a browser bug. The service worker lifecycle protects active pages from an unplanned mid-session switch. Your release plan should work with that lifecycle.

Choose the activation rule before deployment. Immediate takeover is safe only when old pages, new fetch logic and both cache generations can work together.

Start with the default waiting phase

When an updated worker installs successfully, it normally waits while the current worker controls open clients. It activates later. The handoff waits until the old worker no longer controls clients.

A normal refresh may not be enough because the old page can remain a client during navigation. Users with several open tabs can keep the update waiting even longer.

This delay has a purpose. It reduces the chance that one page loads half its resources through the old worker and the rest through new fetch rules.

Treat skipWaiting as a compatibility decision

self.skipWaiting() skips the waiting phase. It does not skip installation. The new worker can activate while pages loaded under the old version are still open.

That is useful for a small, compatible repair. It is risky when HTML, JavaScript chunks, API shapes or cache keys changed together. A later request from an old page may reach logic written for the new page.

Do not add skipWaiting() as boilerplate. Ask one release question: can the new worker correctly handle every request an already-open old page may make?

Activation choiceUse it whenMain risk
Default waitingVersions are not proven compatibleA fix reaches long-lived tabs slowly
User-approved reloadPeople can save work and reload cleanlyA ignored prompt delays the update
Immediate activationOld pages and new worker are compatibleA mixed-version session breaks
Emergency repair workerCached routing or assets are already wrongAssuming every client updates at once

Keep each cache generation separate

Install new assets into a new cache name. Do not overwrite the cache still used by the active worker. If installation fails, the browser can keep the working generation.

const PREFIX = 'acme-app-';
const CACHE = `${PREFIX}v42`;

self.addEventListener('install', event => {
  event.waitUntil(caches.open(CACHE).then(cache =>
    cache.addAll(['/offline.html', '/app-v42.js'])
  ));
});

self.addEventListener('activate', event => {
  event.waitUntil(caches.keys().then(keys =>
    Promise.all(keys
      .filter(key => key.startsWith(PREFIX) && key !== CACHE)
      .map(key => caches.delete(key)))
  ));
});

CacheStorage.delete() removes the named cache. Cache storage belongs to the origin, so a broad cleanup can delete data owned by another app on the same host. Prefix names and delete only your set.

Activation may jump across several releases. Write cleanup and migration code so it can move from an older known state, not only from the version deployed yesterday.

Offer a controlled update for long sessions

An app can detect a waiting worker and show a clear update prompt. Let the user save work first. After approval, send the waiting worker a message that calls skipWaiting(), then reload once when the controller changes.

Guard against a reload loop. Record that the current handoff was already accepted, and clear the guard after the new page is stable.

clients.claim() lets an active worker control eligible pages that were not controlled. That can surprise an existing page. Use it only when that first-load takeover is part of the tested design.

For a long-running dashboard, registration.update() can request an update check. That still does not prove the worker installed, activated or served the right assets.

Rollback with another worker revision

Keep the service worker script at one stable URL. Changing it to a versioned URL can trap users if the old worker keeps serving HTML that registers the old address.

For an emergency rollback, restore compatible server files and deploy a new worker revision at the same script URL. The repair worker can stop serving a broken cache, prefer the network for affected routes or restore the prior known cache rules.

Do not delete the script and assume the registration disappears. Do not promise an instant fleet-wide change. Some clients will be offline, suspended or still waiting to check.

Keep the last good asset set available during the rollback window. Pair it with the digest-based release identity used by your backend. If a certificate or CDN path also changed, use the live TLS verification workflow.

Test the handoff, not just a fresh install

  1. Open two tabs on the old build. Keep one idle and use the other during deployment.
  2. Ship the new worker. Confirm whether it installs, waits and activates under the chosen rule.
  3. Mix the versions. Exercise old-page API calls, lazy chunks, navigation and offline fallback.
  4. Fail the install. Remove one staged asset and confirm the working worker remains active.
  5. Run the repair. Deploy the rollback worker at the same URL and confirm each client state recovers.
  6. Inspect caches. Verify only app-prefixed, approved generations remain.

These are test cases for your environment. TechWeb did not test your service worker, browser mix or CDN. Back up state first; the restore-test guide explains why a saved copy needs a recovery drill.

Header changes can also alter embedded paths. Keep the CSP rollout checklist nearby when a repair adds a new script, worker or network origin.

Frequently asked questions

Should every service worker call skipWaiting?

No. Use it only when the new worker can safely handle pages and requests created by the old version.

Why is the new worker still waiting after refresh?

The current page can remain a controlled client during navigation. Close or leave all controlled tabs, or use a tested update prompt.

Can activation delete every old cache?

Delete only caches owned by this app. Cache storage is shared by the origin, and clients may skip several versions.

Does a server rollback remove the active worker?

No. Publish a compatible repair worker at the stable script URL and verify recovery across real client states.

Sources

W3C: Service Workers specification · web.dev: The service worker lifecycle · MDN: skipWaiting() · MDN: Clients.claim() · MDN: CacheStorage.delete(). Browser behavior and framework helpers can change; test the target versions before rollout.

More in this sectionTechnology →