# Caching strategies for service workers

> The five standard caching strategies — Cache First, Network First, Stale-While-Revalidate, Network Only, Cache Only — when to use each, and how Workbox implements them.

**In one line:** A caching strategy is the rule your service worker follows when a `fetch` event fires — whether to go to the cache, the network, or both, and in what order. The five standard strategies cover every offline and performance trade-off a PWA needs.

## The five strategies

### Cache First (cache falling back to network)

Check the cache first. On a hit, return the cached response. On a miss, fetch from the network and optionally store the result.

**Best for:** Static assets with long-lived content (app shell, fonts, images, versioned JS bundles). Cache hits are instant; misses pay the full network round-trip.

**Avoid for:** Any resource that must always be fresh (user data, prices, auth tokens).

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

### Network First (network falling back to cache)

Try the network. On success, cache and return the fresh response. On network failure, fall back to whatever is cached.

**Best for:** Pages that should be current but tolerate a stale offline fallback (news feeds, dashboards).

**Avoid for:** Large, infrequently changing assets — every request pays the network penalty.

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

### Stale-While-Revalidate

Return the cached version immediately (fast), then fetch a fresh copy in the background and update the cache for next time.

**Best for:** Resources where speed matters more than absolute freshness (avatar images, non-critical API data, secondary scripts). The user always sees something fast; the background fetch keeps the cache warm.

**Avoid for:** Resources where the stale copy can cause errors if loaded alongside fresher content in the same page load.

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

### Network Only

Always go to the network. The service worker does not cache anything.

**Best for:** Requests that must never be served stale: analytics pings, POST mutations, payment requests. Effectively a passthrough.

### Cache Only

Only serve from the cache. If nothing is cached, the request fails.

**Best for:** Resources that were pre-cached during `install` and are guaranteed to exist (the offline shell). Never use for dynamic or user-specific content.

## Choosing a strategy

| Resource type | Recommended strategy |
|---|---|
| App shell (HTML, CSS, core JS) | Cache First with version-keyed cache names |
| Versioned static assets (`/assets/main.abc123.js`) | Cache First — the URL itself changes on deploy |
| API responses, pages that should be current | Network First with offline fallback |
| Avatars, thumbnail images, secondary fonts | Stale-While-Revalidate |
| Auth, payments, analytics | Network Only |
| Offline fallback page | Cache Only (pre-cached in `install`) |

## Using Workbox

Workbox implements all five strategies as composable classes, removing the need for hand-rolled `fetch` event handlers:

```js
import { registerRoute } from 'workbox-routing';
import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';

// App shell — cache first, only cache 200 responses
registerRoute(
  ({ request }) => request.mode === 'navigate',
  new NetworkFirst({ cacheName: 'pages' })
);

// Images — stale-while-revalidate
registerRoute(
  ({ request }) => request.destination === 'image',
  new StaleWhileRevalidate({ cacheName: 'images' })
);

// Versioned assets — cache first, long-lived
registerRoute(
  ({ url }) => url.pathname.startsWith('/assets/'),
  new CacheFirst({
    cacheName: 'static-assets',
    plugins: [new CacheableResponsePlugin({ statuses: [200] })],
  })
);
```

See [Workbox](/reference/service-worker/workbox/) for full setup details.

## Practical checklist

- [ ] Choose a strategy per resource type, not one strategy for everything.
- [ ] Version cache names (e.g. `shell-v3`) and delete old caches in `activate`.
- [ ] Never cache non-idempotent requests (POST, PUT, DELETE) unless you're intentionally building a background sync queue.
- [ ] For Cache First assets, tie the URL to the content hash so stale content is never served from cache after a deploy.
- [ ] Add an explicit offline fallback page so Network First misses produce a usable response, not a browser error. See [Offline fallback](/reference/service-worker/offline-fallback/).

## Cross-references

- [The Cache API](/reference/service-worker/cache-api/) — `caches.open()`, `cache.put()`, and `cache.match()` primitives
- [The Fetch event and routing](/reference/service-worker/fetch-event/) — how `fetch` events reach the service worker
- [Workbox](/reference/service-worker/workbox/) — production-ready strategy implementations
- [Offline fallback](/reference/service-worker/offline-fallback/) — serving a meaningful offline page