Service workers are a browser API that most developers have heard of but few have shipped with confidence. They sit between your code and the network, intercept every request, and give you precise control over caching, offline behavior, and background sync. Whether that control is worth the complexity depends on what your site actually does.
What a service worker is
A service worker is a JavaScript file that runs in a separate thread from the page. It has no DOM access. Its job is to act as a programmable proxy: it intercepts network requests and decides whether to serve them from a cache, pass them through to the network, or return a synthetic response entirely.
The lifecycle has three stages: install, activate, and fetch. On first load, the browser downloads and installs the worker script. On activate, the worker can claim the page and clear stale caches. From that point on, every request the page makes passes through the fetch event handler, where your caching logic lives.
One point worth stating clearly: a service worker is not a server-side process, a CDN layer, or a build-time optimization. It runs in the browser, on the user’s device. Its cache is the browser cache. If the user clears site data, the cache goes with it.
The caching strategies that matter
Most production service workers combine two or three of these patterns.
Cache-first (cache falling back to network): Check the cache; if the asset is there, serve it immediately without touching the network. This is the fastest possible response for assets that rarely change: versioned CSS/JS bundles, fonts, images. The risk is stale content if your invalidation logic is wrong.
Network-first (network falling back to cache): Try the network; if it fails or times out, fall back to the last cached response. Good for HTML pages and API calls where freshness matters but some offline resilience is worth having.
Stale-while-revalidate: Serve from cache immediately, then fetch a fresh version in the background and store it for the next request. This pattern makes sites feel instant without sacrificing currency. It works well for content that updates occasionally, not on every load.
Network only: Pass everything straight through. Useful for payment flows or requests where a stale response would cause real damage.
The most common mistake is reaching for cache-first everywhere. A service worker that caches your HTML cache-first will serve users a stale page even after you’ve deployed a fix. Get the invalidation right, or use stale-while-revalidate for HTML and network-first for authenticated endpoints.
What makes a Progressive Web App
A Progressive Web App is a web site that meets a set of browser criteria allowing it to be installed to a device’s home screen and, optionally, run offline. The three formal requirements are: a valid HTTPS origin, a web app manifest (a JSON file that describes the app’s name, icons, and display mode), and a registered service worker with at least a basic fetch handler.
That is the technical floor. Beyond the install prompt, you get:
- Home screen icon and splash screen drawn from the manifest’s icons and theme color.
- Standalone display mode, which strips the browser chrome so the app looks native.
- Offline capability, to whatever degree your service worker implements it.
- Background sync, so form submissions queued while offline are sent when connectivity returns.
- Push notifications on Android. iOS added partial support in Safari 16.4, with limitations around background processing that remain real in 2026.
Installation is now broadly supported: Chrome, Edge, Firefox on Android, and Safari 17 on macOS and iOS. The gap has narrowed. iOS still restricts certain background capabilities, but for read-heavy use cases those gaps rarely block a useful PWA.
When you actually need one
A service worker adds complexity. You are writing caching logic that runs in an entirely separate execution context, and debugging it requires different tools than the rest of your app. Versioning the worker file so browsers reliably pick up updates is a non-trivial detail. Workbox, the library Google maintains, handles most of the boilerplate, but the decisions about what to cache and with which strategy stay yours.
The cases where a PWA earns its cost:
- Users work in unreliable network conditions. Field technicians, logistics workers, users in markets with patchy connectivity. If your users genuinely lose the network mid-session, offline support is not optional.
- The experience is app-like in practice. If someone opens your site daily to check a dashboard or fill out a form, install-to-home-screen improves their return path in a way that a browser bookmark never does.
- Push notifications without a native app budget. PWA push on Android reaches users without an App Store submission or a React Native build.
- You want aggressive performance on repeat visits. A caching strategy tuned to your asset profile can make second-visit load times feel immediate. Even edge rendering cannot beat assets that never leave the device.
For a standard marketing site or editorial blog, the calculus is different. Caching static assets is already handled by the CDN and the browser’s HTTP cache. A JAMstack architecture gets you much of the performance benefit without a service worker at all. Adding one mainly for an offline fallback page is a reasonable, low-complexity choice, but it is not a significant capability upgrade.
The rendering strategy you choose will move the performance needle more than a service worker will on most marketing sites. A service worker is a caching layer; the rendering architecture is what determines how much work there is to cache in the first place. These are decisions that belong in the same conversation, which is why choosing your web tech stack is worth reading before adding any layer of infrastructure.
How Strynal approaches service workers and PWAs
We treat PWA capability as a feature, not a default. The first question is whether the use case justifies the cache management discipline, because a service worker that is wrong is worse than no service worker. A stale-cache bug that feeds users outdated HTML is invisible in testing and corrosive in production.
For clients who genuinely need offline access or home-screen install, we implement with Workbox, keep caching strategies explicit in code comments, and write tests around the update flow. For marketing sites and content-driven builds, we skip the service worker unless there is a clear performance or reach argument to make.
Our websites and apps practice covers the full decision: architecture, rendering, caching, and the degree of PWA capability appropriate for the project. If you are unsure whether a service worker belongs in your build, that is a short conversation. It starts with what your users actually do.