Skip to content

Service Worker · API

Cache API

Published

The Cache API is an origin-scoped, persistent store of Request/Response pairs reached through the caches global (a CacheStorage) in both service workers and pages. Nothing is written or evicted except by your code or by storage-pressure eviction of the whole origin. It is available in Chrome 43, Edge 16, Firefox 41, and Safari 11.1 in secure contexts only (BCD api.CacheStorage).

// The caches global
const cache = await caches.open(cacheName);
const hit = await caches.match(request, options);
const exists = await caches.has(cacheName);
const names = await caches.keys();
const removed = await caches.delete(cacheName);
// Cache
await cache.add(request);
await cache.addAll([request1, request2]);
await cache.put(request, response);
const response = await cache.match(request, options);
const responses = await cache.matchAll(request, options);
const requests = await cache.keys(request, options);
const deleted = await cache.delete(request, options);

Every method returns a promise. A request argument may be a Request or a URL string, which is resolved against the worker’s or page’s location. caches.open() creates the cache when it does not exist.

CacheStorage manages named caches; Cache holds the entries of one of them.

Member Returns Behaviour
caches.open(name) Promise<Cache> Opens or creates the named cache. Names are arbitrary strings, which is what makes versioning (shell-v3) possible.
caches.match(request, options) Promise<Response | undefined> Searches every cache of the origin in creation order and resolves with the first hit. options.cacheName restricts the search to one cache.
caches.has(name), caches.keys(), caches.delete(name) Promise<boolean>, Promise<string[]>, Promise<boolean> Inventory and removal of whole caches. delete() resolves false when the name did not exist.
cache.add(request) Promise<void> Fetches the request and stores the response. Shorthand for fetch() followed by put().
cache.addAll(requests) Promise<void> Fetches all requests and stores them atomically: when one fails, none is stored.
cache.put(request, response) Promise<void> Stores a response you already hold, without fetching. The body stream is consumed, so clone() first when you also return it.
cache.match(request, options) Promise<Response | undefined> Looks up one entry in this cache.
cache.matchAll(request, options) Promise<Response[]> All entries matching the request, or every entry when request is omitted.
cache.keys(request, options) Promise<Request[]> The stored Request objects, useful for pruning by URL.
cache.delete(request, options) Promise<boolean> Removes matching entries; resolves true when at least one was removed.

options is a CacheQueryOptions dictionary: ignoreSearch drops the query string from the comparison, ignoreMethod lets a non-GET request match a stored GET entry, and ignoreVary skips Vary header matching. Entries are keyed by URL and method, and a stored response’s Vary header is honoured by default, so a request with a different Accept-Language can miss an entry that the DevTools view shows as present.

Rejections carry a DOMException or a TypeError.

  • TypeError: the request method is not GET (add, addAll, put), the request scheme is not http: or https:, the response has status 206, or its Vary header contains *. Chromium’s messages include Partial response (status code 206) is unsupported and Vary header contains *.
  • TypeError from add() and addAll(): a fetched response is not ok (status outside 200 to 299) or the fetch fails. Chromium reports Request failed, so one 404 in a precache list aborts the whole addAll() and, when it runs inside install’s waitUntil(), the install.
  • QuotaExceededError: the origin’s storage quota is exhausted when put(), add(), or addAll() writes. Chromium pads opaque (no-cors, status 0) responses to about 7 MB each in quota accounting, so a handful of third-party assets can trigger it on a near-full device.
  • SecurityError: caches is accessed from an insecure context. On an http: origin other than localhost, window.caches is undefined and self.caches is unavailable in workers.

The two examples below are the install and activate halves of the versioned-cache pattern, followed by a detection example for pages that must run where caches is absent.

Precaching the app shell atomically in install

Section titled “Precaching the app shell atomically in install”

Use addAll() inside event.waitUntil() so that a single failed asset keeps the broken worker out of the active slot.

const SHELL = 'shell-v3';
const ASSETS = ['/', '/app.js', '/app.css', '/offline.html'];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(SHELL).then((cache) => cache.addAll(ASSETS))
);
});

Because addAll() is atomic, shell-v3 is either complete or absent; a 404 on /app.css rejects the promise, the install fails, and the previously active worker keeps serving.

Old caches are not removed for you. Delete every name that is not the current one once the new worker activates.

self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((names) =>
Promise.all(names.filter((n) => n !== SHELL).map((n) => caches.delete(n)))
)
);
});

Run this in activate, not install: during install the old worker may still be serving pages from the cache you would be deleting.

Detecting support and running online-only without it

Section titled “Detecting support and running online-only without it”

caches is missing on insecure origins and in browsers without the API. The fallback below skips service worker registration and tells the app not to advertise offline support.

export function initOffline() {
if ('caches' in window && 'serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
return { offline: true };
}
// No Cache Storage: run online-only and hide the "Available offline" badge.
return { offline: false };
}

Pages that call caches.open() directly should guard the same way; a bare call on an http: origin throws before any promise is created.

Specifications

SpecificationStatus
None.