Skip to content

Caching Strategies

Caching Strategies for PWAs

Caching is a cornerstone of PWA performance, enabling fast load times and offline functionality. The choice of caching strategy depends on your app’s requirements, such as freshness of content, user experience, and network reliability. Below are three core strategies—cache-first, network-first, and stale-while-revalidate—with practical examples.


Cache-First Strategy

Definition: Serve cached content first, falling back to the network if the cache is stale.
Use Cases: Static assets (e.g., images, CSS), scenarios where offline access is critical.
Pros: Fast load times, minimal network dependency.
Cons: Risks serving outdated content if the cache isn't invalidated.

Example: Cache-First

// sw.js
async function cacheFirst(request) {
  const cached = await caches.match(request);
  if (cached) {
    return cached;
  }
  try {
    const response = await fetch(request);
    const newResponse = response.clone();
    const cache = await caches.open('v1');
    await cache.put(request, newResponse);
    return response;
  } catch (error) {
    return new Response('Network error', { status: 503 });
  }
}

self.addEventListener('fetch', (event) => {
  event.respondWith(cacheFirst(event.request));
});

Diagram:

Request → Check Cache → Use Cache (if found)  
                ↓  
                Fetch from Network → Update Cache  


Network-First Strategy

Definition: Prioritize fetching fresh data from the network, then cache it for future use.
Use Cases: Dynamic content (e.g., user data, real-time updates).
Pros: Ensures up-to-date content, avoids stale data.
Cons: Slower initial load times, higher network dependency.

Example: Network-First

// sw.js
async function networkFirst(request) {
  const cache = await caches.open('v1');
  try {
    const response = await fetch(request);
    await cache.put(request, response.clone());
    return response;
  } catch (error) {
    const cached = await cache.match(request);
    return cached || new Response('Network error', { status: 503 });
  }
}

self.addEventListener('fetch', (event) => {
  event.respondWith(networkFirst(event.request));
});

Diagram:

Request → Fetch from Network → Cache Response → Return Response  
                ↓ (if cache miss)  
                Use Cached Response (if available)  


Stale-While-Revalidate Strategy

Definition: Serve cached content immediately while fetching a fresh version in the background.
Use Cases: Balances freshness and performance (e.g., news articles, dashboards).
Pros: Fast initial load, background updates for freshness.
Cons: Slightly more complex to implement.

Example: Stale-While-Revalidate

// sw.js
async function staleWhileRevalidate(request) {
  const cache = await caches.open('v1');
  const cached = await cache.match(request);
  const response = await fetch(request);
  await cache.put(request, response.clone());
  return cached || response;
}

self.addEventListener('fetch', (event) => {
  event.respondWith(staleWhileRevalidate(event.request));
});

Diagram:

Request → Serve Cached Response (immediately)  
                ↓ (background)  
                Fetch from Network → Update Cache  


Key Takeaways

  • Cache-first is ideal for static assets but risks stale data.
  • Network-first ensures freshness but may slow initial loads.
  • Stale-while-revalidate balances performance and freshness, suitable for most PWAs.
  • Always pair caching strategies with cache versioning and expiration policies.
  • Use cache.match() and cache.put() to manage cached responses effectively.