Progressive Web Apps
A Progressive Web App (PWA) is a web app with native-app-like features: offline support, push notifications, installable on home screen, background sync. Built using web standards: service workers, manifests, web APIs.
The PWA promise was that one codebase replaces native apps. The reality is more nuanced.
The core technologies
Service workers
A JavaScript worker that runs separately from your page. It can intercept network requests, cache responses, work offline.
```javascript
// Register
navigator.serviceWorker.register('/sw.js');
// In sw.js
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
```
Service workers enable:
- Offline support (cached responses when network is unavailable)
- Background sync (queue requests; send when online)
- Push notifications
Web App Manifest
A JSON file describing the app:
```json
{
"name": "My App",
"short_name": "MyApp",
"start_url": "/",
"display": "standalone",
"icons": [...]
}
```
The browser uses this for "install to home screen" — the app gets its own icon and runs in a standalone window.
Cache API
Programmatic control over what's cached. Used inside service workers.
Push API
For server-to-client push notifications via a push service (Firebase Cloud Messaging, etc.).
What PWAs do well
Offline support
Cached resources serve when network is down. For content-reading use cases (news, docs), this is significant.
Reliable performance
Cached assets load instantly. Less network dependency.
Installable
Users can add to home screen; the app feels more committed than a website.
Rich web APIs
Background sync, push notifications, file system access, camera, geolocation — increasingly available via web APIs.
What PWAs don't do (or do imperfectly)
Match native performance
Heavy graphics (games, video editing), tight integration with OS features. Native is still ahead for these.
iOS feature parity
Apple has historically been slow to adopt PWA features. Push notifications on iOS Safari only arrived recently. Some features still missing.
App store distribution
Most users find apps via App Store / Play Store. PWAs aren't there by default (though some stores accept them).
Deep OS integration
Native app developer experience for things like share extensions, widgets, watch apps.
The honest assessment
PWAs work well for:
- Content sites that benefit from offline reading
- Productivity apps
- Mobile-friendly versions of web apps
- Internal tools
PWAs work less well for:
- Games
- Video/audio editing
- iOS-first audiences
- Apps that need deep OS integration
For many use cases, "make the website work great offline" is sufficient. For others, native or React Native is the answer.
The Service Worker patterns
Cache-first
Try cache; fall back to network.
```javascript
caches.match(request)
.then(cached => cached || fetch(request))
```
For static assets that rarely change.
Network-first
Try network; fall back to cache.
```javascript
fetch(request).catch(() => caches.match(request))
```
For data that should be fresh; cache as fallback.
Stale-while-revalidate
Serve cached; update cache in background.
```javascript
caches.match(request).then(cached => {
fetch(request).then(fresh => cache.put(request, fresh));
return cached || fetch(request);
});
```
Best of both for most resources.
Cache only
Serve from cache; never go to network. For truly static content.
Network only
Always go to network. For requests that must be fresh.
Implementation considerations
Service worker debugging
Service workers can be tricky to debug. They cache aggressively; old service workers persist. DevTools have specific service worker panels.
Update strategies
When a new service worker is published, the old one is still running for existing tabs. Until tabs close, users see old behavior. Strategies:
- Force reload on update
- Notify user; let them refresh
- Wait for natural tab close
Storage limits
Browsers limit cache storage (varies by browser; tens to hundreds of MB). Plan caching strategy accordingly.
HTTPS required
Service workers require HTTPS (or localhost). Production PWAs need TLS.
Tools
Workbox
Google library for service worker patterns. Reduces boilerplate.
PWA frameworks
Next.js, Nuxt, SvelteKit — all have PWA plugins or built-in support.
Lighthouse
Browser tool; audits PWA conformance. Useful for checking compliance.
Common failure patterns
- **Aggressive caching breaking the app.** Updates don't reach users.
- **No service worker update strategy.** Old code persists forever.
- **Pretending PWA = native.** Some users will need native; PWA isn't always enough.
- **Heavy framework on small content site.** Bundle size hurts the offline-load benefit.
- **Push notifications used badly.** Spam erodes trust.
Further Reading
- [ServerSideRendering](ServerSideRendering) — Adjacent rendering pattern
- [WebComponents](WebComponents) — Component model
- [FormHandlingAndValidation](FormHandlingAndValidation) — UI input
- [FrontendDevelopment Hub](FrontendDevelopmentHub) — Cluster index