Skip to content

Client-Side Caching: Browsers, Local Storage, and Service Workers

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about Client. We cover key concepts, practical examples, and best practices to help you master this topic.

Client-side Caching stores responses directly on the user's device using browser HTTP caches, local storage, IndexedDB, or service workers. This eliminates network round trips entirely for cached resources, resulting in instant load times and offline capability.

flowchart LR
    A[Browser Request] --> B{Service Worker?}
    B -->|Yes, cached| C[Return from SW Cache]
    B -->|No SW| D{HTTP Cache Valid?}
    D -->|Yes| E[Return from Disk Cache]
    D -->|No| F[Fetch from Network]
    F --> G[Update Cache]
    G --> H[Return Response]

What You'll Learn

  • How browser HTTP caches interpret Cache-Control and Expires headers
  • Using localStorage, sessionStorage, and IndexedDB for structured data caching
  • Service worker cache strategies: Cache First, Network First, Stale-While-Revalidate

Why It Matters

Client-side caching is the fastest cache layer because it requires no network call. Properly configured, it can serve assets in under 10ms and enable offline functionality, directly improving user experience metrics like Core Web Vitals.

Real-World Use

A news PWA uses a service worker to cache the homepage and article content with a Cache First Strategy. On subsequent visits, the page loads from cache instantly, then the service worker fetches updates in the background (stale-while-revalidate) and refreshes the UI when new content arrives.

Service Worker Cache Strategies

Cache First (Offline-First)

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((cached) => {
      return cached || fetch(event.request).then((response) => {
        return caches.open('v1').then((cache) => {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    })
  );
});

Expected output:

On first visit: fetches from network, caches response. On subsequent visits: returns cached response instantly.

Stale-While-Revalidate

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.open('dynamic').then((cache) => {
      return cache.match(event.request).then((cached) => {
        const fetchPromise = fetch(event.request).then((response) => {
          cache.put(event.request, response.clone());
          return response;
        });
        return cached || fetchPromise;
      });
    })
  );
});

Expected output:

Returns cached response immediately (may be stale), then fetches update in background and updates cache for next request.

Network First with Fallback

self.addEventListener('fetch', (event) => {
  event.respondWith(
    fetch(event.request).catch(() => {
      return caches.match(event.request);
    })
  );
});

Expected output:

Attempts network first. If offline or network fails, falls back to cached response. Ideal for API calls.

Common Mistakes

  • Caching sensitive user data in localStorage without encryption or expiry.
  • Using Cache First for dynamic data like user profiles or cart contents, serving stale information.
  • Not versioning cache names in service workers, causing old caches to persist and consume storage.
  • Over-caching large media files without limits, filling the browser's storage quota.
  • Failing to handle cache cleanup when the user logs out, leaking data between sessions.

Practice Questions

  1. What is the difference between localStorage and sessionStorage?
  2. How does a service worker intercept network requests?
  3. When would you use Network First instead of Cache First?
  4. What is the purpose of the clone() call when caching a fetch response?
  5. How do browser storage quotas affect your caching strategy?

Challenge

Build a service worker for a weather app that caches the current location's forecast with Cache First (5 min TTL) and caches static assets on install. When the cache is stale but network is unavailable, show a banner indicating stale data.

FAQ

What is the difference between Cache-Control: no-cache and no-store?

no-cache means the browser must revalidate with the server before using the cached response. no-store means the response must not be cached at all.

Can service workers work on all browsers?

Service workers are supported in all modern browsers (Chrome, Firefox, Edge, Safari 11.1+). They require HTTPS except on localhost for development.

What happens when the browser storage quota is full?

When quota is exceeded, the browser throws a QuotaExceededError. Service worker caches are typically excluded from the LRU eviction the browser applies to other storage.

Is localStorage suitable for large data?

No. localStorage is synchronous and limited to ~5-10MB. For larger data, use IndexedDB which is asynchronous and has much higher limits.

How do I clear old service worker caches?

Use the activate event to iterate and delete caches whose names don't match your current version: caches.delete(oldCacheName).

Mini Project

Create a simple HTML page with a service worker that caches all CSS, JS, and images on install. Add a button to toggle between Cache First and Network First strategies. Log which strategy served each resource in the console.

What's Next

Continue with Server-Side Caching to learn about application-level and reverse-proxy caching.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro