A PWA is a web app that uses service workers, a manifest, and HTTPS to be installable, work offline, and receive push notifications. Coined by Alex Russell and Frances Berriman in 2015, it closes the gap between a website and an installed app without leaving the web: one codebase, a home-screen icon, a standalone window, and a screen that keeps working when the train enters a tunnel. The angle this glossary adds, and the one the frontend explainers skip: a PWA is still a client — the service worker caches, but your backend is the source of truth.
Key takeaways
| Question | Answer |
|---|---|
| The three pillars | Service worker · web app manifest · HTTPS |
| What it adds | Installable · offline-capable · push-enabled — over one codebase |
| vs. a responsive site | Adds a service worker + manifest; layout alone isn’t a PWA |
| vs. native | Reach and speed vs. hardware access and store presence |
| The backend truth | The SW cache mirrors; the API/BaaS is authoritative |
The three pillars, and the backend behind them
// JavaScript — the PWA's three pillars + the backend behind them
// 1 · Service worker: caches the shell, buffers writes when offline
navigator.serviceWorker.register('/sw.js');
// 2 · Manifest (public/manifest.json) makes it installable:
// { "name": "Notes", "display": "standalone", "start_url": "/", "icons": [...] }
// 3 · HTTPS is required — service workers refuse to run otherwise.
// The catch: the SW cache is a MIRROR, not the source of truth.
// When back online, queued writes sync to the real backend:
const note = new Parse.Object('Note').set('text', draft);
await note.save(); // the BaaS is authoritative; the cache was a buffer // Flutter / Dart — Back4app Flutter SDK (Flutter web compiles to a PWA)
// The service worker caches the app shell; data still lives on the backend.
final note = ParseObject('Note')..set('text', draft);
await note.save();
// Offline-first pattern: write locally, queue, and sync when connectivity
// returns — the API/BaaS is the source of truth, the cache is a local mirror.
// Push notifications need a BACKEND to send them; the client only subscribes. // Swift — a native shell can host a PWA/WebView; the backend is shared
// The point of parity: whatever the client (PWA, native, web), the
// source of truth is the same backend API.
var note = Note()
note.text = draft
_ = try await note.save()
// Offline-first: cache locally, sync when online — the API is authoritative.
// Web push (PWA) and native push (APNs) both need a backend to SEND them. // Kotlin — a native shell can host a PWA/WebView; the backend is shared
// The point of parity: whatever the client (PWA, native, web), the
// source of truth is the same backend API.
val note = ParseObject("Note")
note.put("text", draft)
note.save()
// Offline-first: cache locally, sync when online — the API is authoritative.
// Web push (PWA) and native push (APNs/FCM) both need a backend to SEND them. A service worker is a background script that sits between the app and the network as a proxy — it caches the shell and serves it offline; a web app manifest is JSON metadata (name, icons, display: standalone, start URL) that makes the app installable; and HTTPS is mandatory, because service workers refuse to run outside a secure context. Those three make the front of the app. The save() in the code tabs makes the point behind it: the cache is a mirror, and when the network returns, the write syncs to the authoritative backend.
How a PWA serves a page offline
Offline caching strategies
| Strategy | Serves from | Right for |
|---|---|---|
| Cache-first | Cache, then network | Static assets — shell, icons, fonts |
| Network-first | Network, fall back to cache | Fresh data that must be current |
| Stale-while-revalidate | Cache now, refresh in background | Content that can be a moment stale |
| Cache-only / network-only | One source only | Precached essentials / never-cache calls |
The decision is per-resource, not per-app: the app shell wants cache-first for instant loads; the user’s live data wants network-first for freshness; a feed can take stale-while-revalidate to feel instant and self-correct. Whichever you pick, the cache is a read/write buffer over the API — offline writes queue locally and reconcile on reconnect, which is the same catch-up discipline any offline-first client needs.
Where push notifications actually come from
The mechanism almost no glossary explains, and the reason a PWA needs a backend even to notify. The client only subscribes: it asks permission and receives a subscription endpoint. Sending is a server job — your backend → the browser’s push service → the service worker’s push event → a displayed notification. The service worker can wake to show it with the app closed, but nothing arrives unless a backend sent it, which is why “PWAs have push” is only half a feature without the server half. The push notifications entry covers the delivery chain; the point here is that web push and native push both terminate in your code deciding to send.
PWA vs. native app
| PWA | Native | |
|---|---|---|
| Codebase | One, on the web | One per platform (or cross-platform) |
| Distribution | A URL — no store required | App stores, with review |
| Updates | Instant, server-side | Store release cycle |
| Discoverability | Indexed by search | Store search only |
| Hardware access | Limited (varies by OS) | Full |
| Push reliability | Good on Android, gated on iOS | Reliable via APNs/FCM |
| iOS reality | Safari-only install, push since 16.4 | First-class |
The honest asymmetry lives in the last row: iOS is where PWAs are weakest — installation only through Safari, no automatic install prompt, push only when installed and only on recent versions, and incomplete background sync. On Android and desktop the gap to native is small; on iOS it is the deciding factor for many products.
Common use cases
- Content and commerce — reach, SEO, and low install friction beat a store download for reaching new users.
- Internal tools — installable, offline-tolerant apps for known users without store distribution.
- Offline-first field apps — capture data with no signal, sync when it returns; the cache-as-buffer pattern.
- Cross-platform reach on a budget — one web codebase covering platforms a native build would triple.
- A companion to a native app — the same backend serving a PWA for reach and a native app for depth.
Should you build a PWA? A decision matrix
| Situation | Lean |
|---|---|
| Reach, SEO, low friction, one codebase | PWA |
| Android/desktop primary audience | PWA — the gap to native is small |
| iOS-critical with heavy push reliance | Native, or accept the iOS caveats |
| Heavy graphics, AR, deep hardware | Native |
| Offline-first data capture | PWA with a sync backend |
| Need a store presence | Native (or PWA-in-store where accepted) |
Limitations and trade-offs
- iOS caps the ceiling. Safari-only install, gated push, and background-sync gaps make iOS the constraint that most often decides PWA-versus-native.
- Hardware access is partial. Bluetooth, NFC, contacts, and advanced camera APIs are limited or absent depending on the OS — device-deep apps still want native.
- The cache is not the database. Treating the service worker cache as the source of truth invites lost writes and stale conflicts; it is a buffer over the authoritative backend.
- Push is half-client, half-server. Subscription is easy; a PWA still needs a backend to send, so “offline and push” is a backend feature wearing a frontend badge.
- Discoverability cuts both ways. No store gatekeeping also means no store storefront; you trade curation and install ceremony for a URL.
PWAs on Back4app
Back4app is an open-source Backend-as-a-Service (BaaS) platform that combines a managed database, auto-generated REST and GraphQL APIs, authentication, file storage, and Cloud Code serverless functions. It is the backend half of the feature the frontend pillars only complete: the service worker caches the shell, but Back4app is the source of truth the cache mirrors — authenticated users, synced data reconciling offline writes on reconnect, and the server that actually sends the web push a PWA can only subscribe to. Because one backend serves a PWA, a plain web app, and a native app alike through per-platform SDKs, the cross-platform reach a PWA promises on the frontend is matched by write-once reach on the backend — the client caches, the platform remembers, and the two halves of “installable, offline, and push” finally meet.
Frequently asked questions
What is a PWA?
A web app built with standard web technologies that uses modern browser capabilities to behave like an installed app — a home-screen icon, a standalone window, offline support, and push notifications — all from one codebase delivered over the web. The term was coined by Alex Russell and Frances Berriman in 2015.
What makes an app a PWA?
Three things working together: a service worker (a background script that caches assets and enables offline use and push), a web app manifest (JSON metadata that makes it installable), and HTTPS (service workers refuse to run without a secure context). Installable and reliable regardless of network is the practical bar.
What is a service worker?
A JavaScript file that runs in the background on its own thread, acting as a network proxy between the app and the network. It intercepts requests and serves them from cache or network, which is what enables offline use, background sync, and receiving push messages while the app is closed.
What is the web app manifest?
A JSON file that tells the browser how to install and present the app — its name, icons, theme and background colors, start URL, and display mode. A display mode of standalone hides the browser UI so the installed app looks like a native one. It is the PWA's ID card.
PWA or native app — which is better?
A PWA is faster and cheaper to build, ships one codebase, updates instantly, needs no app store, and is discoverable by search. A native app gets full hardware access, the smoothest UX, more reliable push, and store presence. Choose native for heavy graphics or deep device integration; a PWA for reach and speed to market.
What is the difference between a PWA and a responsive website?
A responsive site only adapts its layout to screen size and needs a connection. A PWA adds installability, offline caching, and push notifications on top. Every PWA is responsive, but a responsive site becomes a PWA only when it adds a service worker and a manifest.
Can PWAs send push notifications?
They can receive web push via the Push and Notification APIs, but the client only subscribes — a backend must actually send. iOS support arrived in 16.4 and only when the PWA is installed to the Home Screen, so web push reaches a narrower audience than native push does.
Do PWAs work offline?
Yes — the service worker caches assets and data, and serves them when the network is gone. Common strategies are cache-first for static assets, network-first for fresh data, and stale-while-revalidate for instant display with a background refresh. Writes made offline queue and sync when connectivity returns.
Can you put a PWA in an app store?
Partly. Android's store accepts PWAs packaged as trusted web activities, and some desktop stores treat them as first-class. Apple's App Store effectively does not — repackaged-website PWAs are routinely rejected — which is part of why iOS remains the PWA's hardest platform.
When is a PWA the right choice?
When reach, search discoverability, low install friction, one codebase, and fast iteration matter more than deep device integration. It is the wrong choice when you need maximum performance, full hardware APIs, guaranteed iOS push, or a prominent App Store presence.