Progressive Web Apps (PWA)

A Progressive Web App is a website that behaves like an installed application: it gets an icon on the home screen or desktop, launches in its own window, keeps working offline, and can receive push notifications. Under the hood it's still your web app — the "app-ness" comes from two additions: a web app manifest and a service worker.

The pitch is one codebase reaching every platform with app-like UX and none of the app-store friction. Twitter/X, Starbucks, Pinterest, and Spotify's web player ship as PWAs, and for content, commerce, and productivity apps the pattern routinely replaces "we should build a native app."

TL;DR

Quick Example

The two files that make a site installable and offline-capable:

Core Concepts

The Service Worker Lifecycle

A service worker is JavaScript that runs separately from your page and proxies its network traffic. Its lifecycle is the part everyone gets wrong:

The "waiting" step exists so two versions never control the same session — but it means deploys don't reach users until they fully close the app. The standard fix is an in-app "Update available — Refresh" toast that calls skipWaiting(), giving users an explicit upgrade path.

Caching Strategies

The service worker chooses per request. The canonical menu:

These mirror the CDN caching vocabulary — the service worker is effectively a CDN edge that lives on the user's device.

Workbox Instead of Hand-Rolling

Raw service workers accumulate subtle bugs (cache versioning, opaque responses, range requests). Google's Workbox packages the patterns:

Framework integrations (vite-plugin-pwa, Next PWA plugins) wire Workbox into your build so the precache manifest updates automatically per deploy.

Installability and App Capabilities

With a valid manifest + service worker over HTTPS, browsers offer installation (Chrome/Edge prompt on desktop and Android; iOS Safari installs via Share → Add to Home Screen). Beyond install, the PWA-adjacent API family covers most "we need native" arguments:

The genuinely native-only remainder: deep OS integration (widgets, Siri/Assistant), some Bluetooth/sensor APIs on iOS, and top-tier game performance.

Offline-First Data

Caching the app shell is the easy half; the hard half is data. The standard architecture:

Reads always hit the local store (instant, offline-capable); writes commit locally and queue for sync. Libraries like RxDB, Dexie, Replicache, and PowerSync implement the sync layer — including the truly hard parts (conflicts, ordering). If your app must work offline rather than merely open offline, this is the actual project.

Common Mistakes

No Update Story

Precache everything with cache-first, ship a bug fix, and discover users are pinned to the broken version for weeks. Always: version your caches, clean up in activate, and surface a refresh prompt when a new worker is waiting.

Caching Authenticated API Responses Carelessly

A cache shared at the origin level serving user A's /api/me to user B after account switch — the service-worker flavor of the CDN personalization leak. Keep auth'd endpoints network-only or key caches carefully and purge on logout.

Treating the SW as Optional Infrastructure Nobody Owns

A forgotten service worker is a production incident generator: it silently controls every request for every returning user. It needs an owner, tests, and a kill switch (a trivial self-unregistering worker you can deploy in emergencies).

Precaching the World

Precaching 40 MB of assets on first visit burns mobile data and slows install. Precache the shell; runtime-cache the rest on demand.

Ignoring iOS Differences

iOS supports PWAs but with quirks: install only via Safari's share menu (no prompt), storage can be evicted more aggressively, and push requires the app to be installed. Test the iOS path explicitly.

FAQ

PWA or native app?

Ask what you actually need. Content, commerce, dashboards, productivity → PWA covers it with one codebase and no store review. Deep OS integration, heavy graphics, or iOS-first polish → native or React Native/Flutter. Many teams ship the PWA first and add native only when a concrete capability demands it.

Do PWAs work on iOS?

Yes, with caveats: installation is manual (Share → Add to Home Screen), Web Push arrived in iOS 16.4 for installed PWAs, and some APIs (Web Bluetooth, background sync) are missing. Android/desktop support is fuller.

Does a PWA help SEO or performance?

Indirectly but meaningfully: the caching work behind a PWA typically transforms repeat-visit performance and Core Web Vitals. The manifest itself doesn't affect ranking.

Can I put a PWA in the app stores?

Yes — Trusted Web Activities wrap PWAs for Google Play, and PWABuilder generates store packages for Play and Microsoft Store. iOS App Store requires more wrapping (and Apple's review is less friendly to thin wrappers).

How do I test service workers?

Chrome DevTools → Application tab (inspect registration, caches, force update, simulate offline), Lighthouse's PWA audit for installability, and Playwright for automated offline scenarios. Always test the second deploy — that's where update bugs live.

Related Topics

References