# Cache Storage: the request/response store behind offline PWAs

> How the Cache Storage API stores Request/Response pairs for offline-capable PWAs — the CacheStorage and Cache interfaces, where it runs, how it differs from the HTTP cache, and the practical rules for versioning and cleanup.

**In one line:** Cache Storage is the programmatic, origin-scoped store for
`Request`/`Response` **pairs** — the mechanism a service worker uses to serve assets and
API responses while offline. You explicitly decide what it holds, unlike the browser's
automatic HTTP cache.

## Cache Storage vs the HTTP cache vs IndexedDB

- **The HTTP cache** is managed automatically by the browser and is separate from Cache
  Storage; the Cache API does not honor HTTP caching headers. You don't directly read or
  write the HTTP cache.
- **Cache Storage** is a store you control directly: you explicitly `put`, `match`, and
  `delete` whole `Response` objects, keyed by `Request`. It is what makes a service worker's
  `fetch` handler able to answer requests with no network.
- **IndexedDB** stores **structured records and blobs**, not HTTP responses. Use it for app
  data (drafts, queued mutations); use Cache Storage for the app shell and fetched assets.

## The two interfaces

- **`CacheStorage`** — exposed as `caches` in windows, workers, and service workers. It is a
  registry of named `Cache` objects: `caches.open(name)`, `caches.has(name)`,
  `caches.delete(name)`, `caches.keys()`, and a convenience `caches.match()` that searches
  across all caches.
- **`Cache`** — a single named store of request→response entries. Key methods:
  - `cache.put(request, response)` — store a pair you already have.
  - `cache.add(request)` / `cache.addAll(requests)` — fetch and store in one step.
  - `cache.match(request)` / `cache.matchAll()` — look up a stored response.
  - `cache.delete(request)` — remove an entry.

A `Cache` stores `Response` objects. Because a response body can only be read once, store a
**clone** when you also want to return the response to the page (`response.clone()`).

## Where it runs and what it is for

`caches` is available in the window, in Web Workers, and — crucially — in service workers,
which is what lets the service worker's `fetch` event answer from the cache when the network
is unavailable. Pre-store the app shell during `install`, then serve from the cache in
`fetch`, falling back to (or updating from) the network per your chosen strategy.

```js
const CACHE = 'shell-v3';
const ASSETS = ['/', '/app.css', '/app.js', '/offline.html'];

self.addEventListener('install', (event) => {
  event.waitUntil(caches.open(CACHE).then((cache) => cache.addAll(ASSETS)));
});

self.addEventListener('activate', (event) => {
  // Delete old caches so a new deploy doesn't serve stale files forever.
  event.waitUntil(
    caches.keys().then((names) =>
      Promise.all(names.filter((n) => n !== CACHE).map((n) => caches.delete(n)))
    )
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((hit) => hit || fetch(event.request))
  );
});
```

## Versioning and cleanup

Cache Storage does not remove your entries on its own under normal use — what you put in
stays until you delete it. That makes a deliberate versioning scheme essential:

- **Name caches with a version** (`shell-v3`). Bump the name when assets change.
- **Delete superseded caches in `activate`**, as above, so the previous version's files are
  reclaimed instead of accumulating.
- **Be careful with opaque responses.** A cross-origin `no-cors` request yields an opaque
  response with status `0`, which can only be stored with `put`; cache these only when you
  must.

## Quota and persistence

Cache Storage data counts toward the origin's storage usage governed by the Storage API,
alongside other web storage such as IndexedDB. Browsers may evict an origin's storage when
quota limits are reached, so treat cached assets as **disposable** and be ready to re-fetch.
Where data must survive eviction, request persistent storage with
`navigator.storage.persist()`. (See the storage persistence reference for the full quota
and eviction model.)

## Browser & ecosystem support

The Cache Storage API (`CacheStorage` and `Cache`) is supported across current major
browsers and is reachable from service workers, making it the baseline offline-asset store
for PWAs.

## Practical checklist

- [ ] Use Cache Storage for request/response assets; use IndexedDB for structured app data.
- [ ] `clone()` a response before caching if you also return it to the page.
- [ ] Name caches with a version and bump the name when assets change.
- [ ] Delete old caches in the service worker's `activate` event.
- [ ] Treat the cache as disposable; design for re-fetch and call `persist()` when data must survive eviction.
- [ ] Be cautious caching opaque cross-origin responses — you cannot inspect them.