Swoff Swoff

Versioned Service Worker

How Swoff versions service workers to prevent silent updates and give users control.

The Problem

Typical SW registration uses a fixed path like /sw.js. The browser automatically downloads and activates new versions on reload — dangerous if the update has breaking changes.

Swoff's Solution: Versioned Filenames

Instead of /sw.js, we use /sw-v1.0.0.js, /sw-v1.0.1.js, etc. Each version is a unique file that the browser only loads when you tell it to.

dist/
├── sw-v1.0.0.js      ← Version 1.0.0
├── sw-v1.0.1.js      ← Version 1.0.1
└── version.json      ← Version manifest

How It Works

Version from package.json

package.json
{
  "name": "my-app",
  "version": "1.0.0"
}

Build Generates Versioned SW

A build script reads the version from package.json, replaces placeholders in the SW template, and outputs a versioned SW file plus version.json. The script is straightforward string replacement — see Build Scripts for the implementation.

Client Checks version.json

On each load, the app fetches version.json and compares the version against the registered SW. If they differ, an update is available. See Client Registration for the implementation.

Update Flow

User opens app

Fetch /version.json → Compare with localStorage['swRegisteredVersion']

Same version? → Use existing SW
New version? → Fire 'sw-update-available' event → Show prompt

User approves → Register new SW → Downloads assets → SKIP_WAITING → Reload

Version Manifest

version.json
{
  "version": "1.0.1",
  "minSupportedVersion": "1.0.0",
  "generatedAt": "2024-01-15T10:30:00.000Z"
}
FieldPurpose
versionSemVer version string of this build
minSupportedVersionMinimum version users must have (enforced update)
generatedAtISO timestamp of build

Users explicitly approve updates. The flow: idle → available → downloading → reload.

Minimum Supported Version (Forced Updates)

When releasing critical updates, set minSupportedVersion in swoff.config.json:

swoff.config.json
{
  "minSupportedVersion": "1.0.5"
}

If the user's registered version is less than minSupportedVersion, the update is mandatory — full-screen overlay with no dismiss option. Otherwise, it's optional (standard bottom-sheet).

Example: v1.0.5 is released with minSupportedVersion: "1.0.5" (security fix). v1.0.6 follows with minSupportedVersion: "1.0.5" (feature). A user on v1.0.4 visiting during v1.0.6 is forced to update because 1.0.4 < 1.0.5.

Users can dismiss optional updates for the current session via sessionStorage — see Client Registration for the implementation.

Events and Window Properties

EventPurpose
sw-update-availableNew version detected
sw-progressDownload progress
sw-readySW active
interface Window {
  latestSWVersion?: string;
  currentSWVersion?: string;
  swMinSupportedVersion?: string;
}

Bumping Versions

npm
npm version patch  # 1.0.0 → 1.0.1
npm version minor  # 1.0.0 → 1.1.0
npm version major  # 1.0.0 → 2.0.0
npm run build

Benefits

  1. No silent updates — users explicitly approve
  2. Rollback possible — re-register the old version
  3. Clear versioning — filename shows exact version
  4. Browser agnostic — works in all browsers with SW support

Next Steps

On this page