Caching

When a user opens and interacts with a website, all the resources that the website needs, including the HTML, JavaScript, CSS, images, fonts, as well as any data explicitly requested by the app, are retrieved by making HTTP(S) requests. One of the most fundamental features of a PWA is the ability to explicitly cache some of the app's resources on the device, meaning that they can be retrieved without needing to send a request to the network.

There are two main benefits to caching resources locally: offline operation and responsiveness.

The main drawback, of course, is freshness: caching is less appropriate for resources which need to be up to date. Also, for some types of requests, such as POST requests, caching is never appropriate.

This means that whether and when you should cache a resource is very dependent on the resource in question, and a PWA will typically adopt different strategies for different resources. In this guide we'll look at some common caching strategies for PWAs, and see which strategies make sense for which resources.

Caching technology overview

The main technologies on which a PWA can build a caching strategy are the Fetch API, the Service Worker API, and the Cache API.

Fetch API

The Fetch API defines a global function fetch() for fetching a network resource, and Request and Response interfaces that represent network requests and responses. The fetch() function takes a Request or a URL as an argument, and returns a Promise that resolves to a Response .

The fetch() function is available to service workers as well as to the main app thread.

Service Worker API

A service worker is a part of a PWA: it's a separate script that runs in its own thread, separate from the app's main thread.

Once the service worker is active, then whenever the app requests a network resource controlled by the service worker, the browser fires an event called fetch in the service worker's global scope. This event is fired not only for explicit fetch() calls from the main thread, but also implicit network requests to load pages and subresources (such as JavaScript, CSS, and images) made by the browser following page navigation.

By listening for the fetch event, the service worker can intercept the request and return a customized Response . In particular, it can return a locally cached response instead of always going to the network, or return a locally cached response if the device is offline.

Cache API

The Cache interface provides persistent storage for Request / Response pairs. It provides methods to add and delete Request / Response pairs, and to look up a cached Response matching a given Request . The cache is available in both the main app thread and the service worker: so it is possible for one thread to add a response there, and the other to retrieve it.

Most commonly, the service worker will add resources to the cache in its install or fetch event handlers.

When to cache resources

A PWA can cache resources at any time, but in practice there are a few times when most PWAs will choose to cache them:

Note: Service worker install time is not the same as PWA install time. A service worker's install event fires as soon as the service worker has been downloaded and executes, which will typically happen as soon as the user visits your site. Even if the user never installs your site as a PWA, its service worker will be installed and activated.

Caching strategies

A caching strategy is an algorithm for when to cache a resource, when to serve a cached resource, and when to get the resource from the network. In this section we'll summarize some common strategies.

This isn't an exhaustive list: it's just intended to illustrate the kinds of approaches a PWA can take.

A caching strategy balances offline operation, responsiveness, and freshness. Different resources have different requirements here: for example, the app's basic UI is likely to be relatively static, while it may be essential to have fresh data when displaying a product listing. This means that a PWA will typically adopt different strategies for different resources, and a single PWA might use all the strategies described here.

Cache first

In this strategy we will precache some resources, and then implement a "cache first" strategy only for those resources. That is: