Cache Storage: the request/response store behind offline PWAs
Published
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
Section titled “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, anddeletewholeResponseobjects, keyed byRequest. It is what makes a service worker’sfetchhandler 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
Section titled “The two interfaces”CacheStorage— exposed ascachesin windows, workers, and service workers. It is a registry of namedCacheobjects:caches.open(name),caches.has(name),caches.delete(name),caches.keys(), and a conveniencecaches.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
Section titled “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.
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
Section titled “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-corsrequest yields an opaque response with status0, which can only be stored withput; cache these only when you must.
Quota and persistence
Section titled “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
Section titled “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
Section titled “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
activateevent. - 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.