The Cache API
The complete Cache API
Section titled “The complete Cache API”The Cache API revolves around two objects: the global CacheStorage (accessed via caches) and the individual Cache objects it manages. All methods are async and return Promises.
caches.open(name)
Section titled “caches.open(name)”Opens an existing named cache or creates a new one if it does not exist. Returns a Cache object. Cache names are arbitrary strings — use versioned names like app-shell-v2 to manage upgrades.
const cache = await caches.open('demo-cache-v1');cache.put(request, response)
Section titled “cache.put(request, response)”Stores a Request/Response pair. The first argument can be a Request object or a URL string; the second must be a Response. Any existing entry for the same request is replaced.
const cache = await caches.open('demo-cache-v1');await cache.put('/api/hello', new Response('{"status":"ok"}', { headers: { 'Content-Type': 'application/json' },}));cache.add(url)
Section titled “cache.add(url)”Fetches the given URL and stores the resulting response in the cache. Equivalent to calling fetch(url) followed by cache.put(url, response). The request must succeed (2xx status) or the cache is not updated.
const cache = await caches.open('demo-cache-v1');await cache.add('/images/logo.png'); // fetches then storescache.addAll(urls)
Section titled “cache.addAll(urls)”Accepts an array of URL strings and fetches all of them atomically. If any request fails, none of the responses are stored. Use this when you need a group of assets to be cached together or not at all.
const cache = await caches.open('demo-cache-v1');await cache.addAll([ '/index.html', '/styles/main.css', '/scripts/app.js',]);cache.match(request, options?)
Section titled “cache.match(request, options?)”Looks up the cache for an entry matching the given request (URL string or Request). Returns the matching Response or undefined if no entry exists. The optional options object accepts ignoreSearch, ignoreMethod, and ignoreVary.
const cache = await caches.open('demo-cache-v1');const response = await cache.match('/api/hello');if (response) { console.log(await response.json());}caches.match(request, options?)
Section titled “caches.match(request, options?)”Like cache.match but searches across all named caches in the current origin, returning the first match found. Useful when you do not know which cache holds a particular response.
const response = await caches.match('/api/hello');cache.delete(request, options?)
Section titled “cache.delete(request, options?)”Removes the entry for the given request from the cache. Returns true if an entry was found and deleted, false otherwise.
const cache = await caches.open('demo-cache-v1');const deleted = await cache.delete('/api/hello');console.log('Deleted:', deleted); // truecaches.keys()
Section titled “caches.keys()”Returns an array of all cache names for the current origin. Use it to enumerate or clean up caches.
const names = await caches.keys();console.log('Open caches:', names);
// Delete all cachesfor (const name of names) { await caches.delete(name);}Runnable: put, match, and clean up
Section titled “Runnable: put, match, and clean up”Trade-offs
Section titled “Trade-offs”| Choice | Benefit | Cost |
|---|---|---|
Store an opaque response (cross-origin, no-cors) with cache.put() | Works with CDN or third-party resources that don’t send CORS headers | Counted against quota at full size even though the body can’t be read, so quota drains without warning |
Use cache.addAll() atomically for pre-caching | Guarantees every declared install asset is present or none are — no partially-cached state | If a single asset 404s, the whole install fails; error handling has to account for that |
Version the cache name (e.g. demo-cache-v2) | Lets you change strategy or update assets without mixing with the old cache | You must delete old cache versions yourself in the activate event, or storage grows without bound |
Common mistakes
Section titled “Common mistakes”- Caching an opaque response and assuming it costs nothing because the body is unreadable — the browser counts an opaque response’s full size (often several MB each) against quota just like a normal response.
- Never deleting old cache versions on deploy — every time the cache name changes (e.g. v1 → v2) you must call
caches.delete()on the old name inside theactivateevent, or storage accumulates forever. - Using
cache.add()/addAll()without checking response status — these methods store a response of any status, including error pages a server may return, without throwing. Check status yourself if that matters.