Progressive Web Apps
What It Is
A Progressive Web App, also called PWA, is a web application built with standard web technologies like HTML, CSS, and JavaScript.
It is designed to feel like a native app by supporting installation, offline usage, fast loading, and app-like behavior across devices.
PWA = Website + App-like experience + Offline support + Installability
Why It Is Called Progressive
The word progressive means the app should work for every user regardless of browser support.
If a browser supports advanced features, the app can provide a richer experience.
If not, the basic web experience should still work.
Basic browser -> normal website
Modern browser -> installable offline-capable app
This idea is based on progressive enhancement.
Core Requirements
A PWA commonly uses these main pieces.
| Requirement | Purpose |
|---|---|
| HTTPS | Required for installability and secure powerful APIs |
| Service Worker | Enables offline behavior and cache/network control |
| Web App Manifest | Describes the app for installation |
Modern installability mainly depends on HTTPS and a valid web app manifest. A service worker is still commonly used for offline support, but current browser install criteria do not always require it.
How PWA Installation Works
When the PWA requirements are satisfied, the browser can show an install prompt.
The user can add the app to:
- mobile home screen
- desktop
- app launcher
After installation, the app can open in its own window without the normal browser address bar.
Install prompt -> User installs -> App opens like native app
Service Worker Role
The service worker is the main piece that enables offline behavior.
Without a service worker:
Browser -> Server
With a service worker:
Browser -> Service Worker -> Cache / Network
The service worker decides whether a request should be served from cache or fetched from the internet.
This gives control over offline behavior and faster repeat visits.
Advantages
PWAs provide many user and business benefits.
| Advantage | Meaning |
|---|---|
| Offline support | Works without internet using cached assets |
| Installable | Can be added to home screen or desktop |
| Fast loading | Cached assets reduce latency |
| Responsive | Works across mobile, tablet, and desktop |
| No app store required | Distributed using a URL |
| Auto-updates | Service worker can update in the background |
| Push notifications | Can re-engage users using Web Push API |
| Lower development cost | One codebase gives web and app-like experience |
| SEO friendly | Discoverable and indexable by search engines |
| Reduced data usage | Cache-first strategy saves bandwidth on repeat visits |
Disadvantages
PWAs also have limitations.
| Disadvantage | Meaning |
|---|---|
| Limited iOS support | Some PWA features are restricted on Apple platforms |
| Restricted native APIs | Some device APIs may not be available |
| Less discoverable | Users may not find it like App Store or Play Store apps |
| Storage pressure | Browser may clear cache when device storage is low |
| Complex debugging | Offline behavior and service worker state can be harder to debug |
| No app store presence | Some users may trust store apps more |
Basic Project Structure
A minimal PWA uses multiple files together.
project/
index.html -> Main HTML file
style.css -> Application styles
script.js -> Registers the service worker
sw.js -> Service worker file
manifest.json -> App metadata for installation
Each file has a specific role.
| File | Purpose |
|---|---|
| index.html | Links manifest and loads app scripts |
| script.js | Registers the service worker |
| sw.js | Handles install, fetch, cache, and activate events |
| manifest.json | Defines app name, icons, colors, display mode, and launch URL |
Registering the Service Worker
The service worker file does not run automatically.
It must be registered from the main JavaScript file, usually script.js.
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("./sw.js")
.then((reg) => {
console.log("Service Worker registered:", reg);
})
.catch((err) => {
console.error("Registration failed:", err);
});
});
}
This code checks whether the browser supports service workers and registers sw.js after the page loads.
script.js -> registers sw.js -> service worker can install and handle fetches
Service Worker Install Event
The install event runs once when the service worker is first installed.
Its main job is to pre-cache important files so the app can work offline later.
const CACHE_NAME = "pwa-demo-v1";
const ASSETS = ["./index.html", "./style.css", "./script.js", "./sample.jpg"];
self.addEventListener("install", (event) => {
console.log("Service Worker installing...");
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
console.log("Caching core assets...");
return cache.addAll(ASSETS);
}),
);
});
event.waitUntil() tells the browser to wait until caching finishes before completing installation.
Install event = prepare important assets for offline usage
Service Worker Fetch Event
The fetch event runs for every network request made by the page.
The example uses a Cache First strategy.
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
if (response) {
console.log("Serving from cache:", event.request.url);
return response;
}
return fetch(event.request).catch(() => {
return caches.match("./index.html");
});
}),
);
});
The flow is:
Check cache first
If found -> return cached response
If missing -> fetch from network
If network fails -> return offline fallback
This strategy works well for static assets like CSS, JS bundles, logos, and images.
Service Worker Activate Event
The activate event runs when a new service worker becomes active.
Its main job is to remove old cache versions.
self.addEventListener("activate", (event) => {
console.log("Service Worker activating...");
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((name) => name !== CACHE_NAME)
.map((name) => {
console.log("Deleting old cache:", name);
return caches.delete(name);
}),
);
}),
);
});
This prevents old assets from staying in the browser cache.
Activate event = clean old cache versions
Linking Manifest in HTML
The manifest file must be linked inside the head of index.html.
The page should also include a theme color.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#4F46E5" />
<link rel="manifest" href="./manifest.json" />
<title>My PWA App</title>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<!-- app content -->
<script src="./script.js"></script>
</body>
</html>
This connects the web page with the app manifest and service worker registration script.
Web App Manifest
The Web App Manifest is a JSON file that tells the browser how the PWA should behave when installed.
It controls:
- app name
- short name
- description
- start URL
- display mode
- theme color
- background color
- orientation
- scope
- icons
Manifest Example
{
"name": "Namaste Frontend System Design",
"short_name": "Namaste",
"description": "Offline-first PWA demonstrating system design concepts",
"start_url": "./index.html",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4F46E5",
"orientation": "portrait-primary",
"scope": "/",
"icons": [
{
"src": "./icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "./icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
Manifest Fields
| Field | Meaning |
|---|---|
| name | Full app name shown on splash screen and OS app list |
| short_name | Short label used on home screen icons |
| description | Brief description used by some browsers and search engines |
| start_url | URL opened when the app launches |
| display | Controls how much browser UI is visible |
| background_color | Splash screen background before CSS loads |
| theme_color | Browser toolbar or status bar color |
| orientation | Locks orientation such as portrait, landscape, or any |
| scope | URL area controlled by the app |
| icons | App icons in different sizes |
Display Modes
The display field controls how the installed app opens.
| Mode | Meaning |
|---|---|
| standalone | Looks like a native app without address bar |
| fullscreen | Uses the full screen, useful for immersive apps |
| minimal-ui | Shows minimal browser controls |
| browser | Opens like a normal website in a browser tab |
Most PWAs commonly use:
{
"display": "standalone"
}
Icon Best Practices
A PWA should include proper icons for installation.
Important practices:
- provide at least
192x192and512x512PNG icons - use
purpose: "maskable"for adaptive Android icons - use
purpose: "any"for standard icons - keep important content inside the center safe area
- use transparent backgrounds for icons
Good icons make the installed PWA look more like a real app.
End-to-End Flow
A PWA works by combining manifest, service worker, cache, and browser install behavior.
1. HTML links manifest and loads script.js
2. script.js registers sw.js
3. install phase caches important assets
4. fetch phase intercepts browser requests
5. cache hit serves file from local cache
6. cache miss fetches from network
7. network failure returns offline fallback
8. activate phase cleans old cache versions
Result:
- faster loading
- offline support
- reduced network dependency
PWA Overview Table
| Part | Purpose |
|---|---|
| PWA | Web app with native app-like experience |
| HTTPS | Required for secure service worker usage |
| Service Worker | Handles cache, fetch, offline support, and updates |
| Manifest | Defines app metadata and install behavior |
| Install Prompt | Lets user add app to home screen or desktop |
| Cache First | Serves cached assets before network |
| Offline Fallback | Shows app shell when network fails |
| Activate Event | Removes old cache versions |
Basic Checklist
Serve the app over HTTPS
Create manifest.json
Add name, short_name, start_url, display, colors, scope, and icons
Link manifest in index.html
Add theme-color meta tag
Create sw.js
Register sw.js from script.js
Cache important assets in install event
Use fetch event for cache-first behavior
Return offline fallback when network fails
Clean old cache versions in activate event
Use proper 192x192 and 512x512 icons
Test install prompt and offline behavior
Interview Style Answer
A Progressive Web App is a web application built with HTML, CSS, and JavaScript that provides an app-like experience through installability, offline support, fast loading, and responsive behavior. A PWA requires HTTPS and a web app manifest for installability in modern browsers, while a service worker is commonly used for offline support and cache control. The manifest defines app metadata like name, icons, theme color, start URL, display mode, and scope. The service worker acts as a proxy between the browser, cache, and network. It registers from script.js, caches important assets during the install event, intercepts requests during the fetch event using a cache-first strategy, returns an offline fallback when the network fails, and cleans old cache versions during activation.
One-Line Summary
PWA = An installable, offline-capable web app powered by HTTPS, Service Worker, and Web App Manifest.
Final Mental Model
Manifest -> makes app installable
Service Worker -> makes app offline-capable
Cache -> makes app fast after first load
HTTPS -> makes powerful browser features safe