Home/Blog/frontend engineering
Back to all articles
frontend engineering#PWA#Service Workers#Offline-First

Building Offline-First Progressive Web Apps (PWAs): Service Workers, Cache Storage & IndexedDB

RB
Rajput BhavinArchitect
Founder, Rajput Bhavin Engineering
24 August 2026•11 min read

Quick Answer: What is an Offline-First PWA?#

⚡ Quick Answer / Executive Summary
An Offline-First Progressive Web App (PWA) is a web application engineered to function reliably regardless of network connectivity. By utilizing Service Workers as client-side programmable network proxies, caching static application shells in the Cache Storage API, persisting offline transactions in IndexedDB, and synchronizing pending mutations via the Background Sync API, PWAs achieve native app-like performance and zero downtime during network drops.

The 3 Architectural Pillars of Offline-First PWAs#

At Rajput Bhavin Engineering, we architect PWAs across three core technical layers:

Architecture Blueprint
System Flow
┌─────────────────────────────────────────────────────────────┐
│                 PWA Offline-First Architecture              │
├─────────────────────┬───────────────────────────────────────┤
│ Web App Manifest    │ Installation metadata & standalone UI │
│ Service Worker      │ Network proxy & caching strategies    │
│ IndexedDB Storage   │ Local structured relational data sync │
└─────────────────────┴───────────────────────────────────────┘

1. Service Worker Caching Strategies Compared#

A Service Worker intercepts every HTTP fetch request made by the browser. Selecting the correct caching strategy per resource type is critical:

StrategyHow It WorksIdeal For
Cache First (Fallback Network)Checks Cache Storage first; fetches network only if missingFonts, static JS chunks, icons, product images
Network First (Fallback Cache)Tries live network; falls back to cached data if offlineReal-time pricing, stock inventory, user profiles
Stale-While-RevalidateServes cached version instantly while fetching update in backgroundNews feeds, blog articles, dashboard navigation
Network OnlyAlways hits live server (never caches)Stripe checkout tokens, authentication login APIs

2. Production Service Worker Implementation (public/sw.js)#

JavaScript
Production Code
const CACHE_NAME = 'rbe-pwa-v1';
const STATIC_ASSETS = [
  '/',
  '/manifest.json',
  '/favicon.ico',
  '/offline.html',
];

// 1. Install Event: Pre-cache core application shell
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.addAll(STATIC_ASSETS);
    })
  );
  self.skipWaiting();
});

// 2. Activate Event: Clean up old versioned caches
self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then((keys) => {
      return Promise.all(
        keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key))
      );
    })
  );
  self.clients.claim();
});

// 3. Fetch Event: Stale-While-Revalidate with Offline Fallback
self.addEventListener('fetch', (event) => {
  if (event.request.method !== 'GET') return;

  event.respondWith(
    caches.open(CACHE_NAME).then(async (cache) => {
      const cachedResponse = await cache.match(event.request);

      const networkFetch = fetch(event.request)
        .then((response) => {
          if (response.status === 200) {
            cache.put(event.request, response.clone());
          }
          return response;
        })
        .catch(async () => {
          // If network fails and no cache exists, return custom offline page
          return cachedResponse || (await cache.match('/offline.html'));
        });

      return cachedResponse || networkFetch;
    })
  );
});

3. Bi-Directional Offline Sync with IndexedDB & Background Sync#

When a field worker, delivery driver, or warehouse manager performs an action offline (such as creating an invoice or updating stock), we persist the mutation in local IndexedDB:

TypeScript
Production Code
import { openDB } from 'idb';

const dbPromise = openDB('offline-mutations-db', 1, {
  upgrade(db) {
    db.createObjectStore('pending-mutations', { keyPath: 'id', autoIncrement: true });
  },
});

export async function queueOfflineAction(endpoint: string, payload: any) {
  const db = await dbPromise;
  await db.add('pending-mutations', {
    endpoint,
    payload,
    timestamp: Date.now(),
  });

  // Register Background Sync if supported
  if ('serviceWorker' in navigator && 'SyncManager' in window) {
    const registration = await navigator.serviceWorker.ready;
    await (registration as any).sync.register('sync-pending-mutations');
  }
}

When the device regains cellular 5G/Wi-Fi connection, the Service Worker background event triggers, replaying queued mutations to the server idempotently.


4. Web App Manifest (public/manifest.json)#

JSON Data
Production Code
{
  "name": "Rajput Bhavin Engineering",
  "short_name": "RBE Portal",
  "description": "High-Performance Software & AI Systems in Ahmedabad",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#050505",
  "theme_color": "#3b82f6",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any maskable"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ]
}

Build Offline-Resilient Web Platforms with Rajput Bhavin#

Ensure your web applications operate seamlessly under spotty mobile connectivity and harsh industrial warehouse environments.

Modern Web Engineering

Building a high-performance web experience?

Rajput Bhavin Engineering builds 100/100 Core Web Vitals websites, web applications, and headless e-commerce stores using Next.js 15, React 19, and Tailwind CSS.

RB

Rajput Bhavin

Systems Architect

Founder and Systems Architect at Rajput Bhavin Engineering in Gota, Ahmedabad. Specializes in high-concurrency cloud software, Next.js web applications, multi-tenant SaaS architecture, and autonomous AI systems.

Connect Now