---
title: "Ship new service workers without trapping · Agent Wranglers"
url: https://agentwranglers.se/playbook/website/when-things-break/service-worker-updates
id: WEB-267
level: Recommended
updated: 2026-10-22
tokens: 858
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Ship new service workers without trapping old ones

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [When things break](https://agentwranglers.se/playbook/website/when-things-break.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: WEB-267
- Level: Recommended
- Chapter: [When things break](https://agentwranglers.se/playbook/website/when-things-break.md)
- Rule: Keep the worker at one fixed address, serve it with `Cache-Control: no-cache`, and keep a worker ready that removes itself.
- Check: `curl -sI https://example.com/sw.js` shows `Cache-Control: no-cache`. In a browser test, deploying a changed worker shows the update notice within one page load. Deploying the removal worker leaves no registration and no caches.
- How: A worker at a hashed address never updates, because pages keep registering the old one. Keep `/sw.js` fixed, and register it with `updateViaCache: 'none'`, so scripts it imports are checked too. When a new worker waits, tell the page and reload at a safe moment, as [Recover when a new release replaces the old files](https://agentwranglers.se/playbook/app-ui/permissions-flags-and-failures/new-release-reload.md) says. Call `skipWaiting` at once only when old pages still work with the new worker. Keep a removal worker in the repository. It clears the caches and unregisters itself, so a broken worker can be undone with one deploy.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
navigator.serviceWorker.register('/sw.js', { updateViaCache: 'none' });

// sw-remove.js, deployed as /sw.js to undo a broken worker
self.addEventListener('install', () => self.skipWaiting());
self.addEventListener('activate', event => event.waitUntil((async () => {
  await Promise.all((await caches.keys()).map(key => caches.delete(key)));
  await self.registration.unregister();
  (await self.clients.matchAll()).forEach(client => client.navigate(client.url));
})()));
```

### Python example

```python
@app.get("/sw.js")
def service_worker():
    return FileResponse("static/sw.js", media_type="text/javascript", headers={"Cache-Control": "no-cache"})
```

## Sources

- [W3C Service Workers](https://www.w3.org/TR/service-workers/)

## Related rules

- APP-53 [Recover when a new release replaces the old files](https://agentwranglers.se/playbook/app-ui/permissions-flags-and-failures/new-release-reload.md) in Web app interface

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/website/when-things-break/service-worker-updates">Agent Wranglers website playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Choose a caching strategy for each kind of request](https://agentwranglers.se/playbook/website/when-things-break/service-worker-strategies.md)
- Next: [Warn before retiring an address](https://agentwranglers.se/playbook/website/when-things-break/deprecation-and-sunset.md)
- [When things break](https://agentwranglers.se/playbook/website/when-things-break.md)
