# Precaching strategies: shipping the app shell ahead of time

> How precaching populates the cache during service-worker install so a PWA's shell loads instantly and offline — what to precache vs runtime-cache, why content revisioning matters, and how Workbox's precache manifest automates it.

**In one line:** *precaching* stores a known, fixed set of files into the cache during the
service worker's **install** step, so the app shell is on the device before it is needed —
the first navigation after install can render instantly and offline. It is the counterpart to
*runtime caching*, which stores responses as the user requests them.

## Precache vs runtime cache

- **Precache** — a fixed list known at build time (HTML shell, CSS, JS, icons, fonts). Fetched
  and stored during `install`, before the page asks for them. Suited to the **app shell** and
  other critical, always-needed assets.
- **Runtime cache** — populated in the `fetch` handler as requests happen, under a chosen
  caching strategy. Suited to content that varies or is too large/numerous to list up front
  (API responses, user images, articles).

Precaching and runtime caching are complementary: precache the shell so the first load is
fast and offline-capable, and runtime-cache the dynamic content around it.

## What to precache (and what not to)

- **Precache:** the minimal app shell — the HTML/CSS/JS and icons needed to render a usable
  first screen. Everything listed here is downloaded and stored during the `install` event.
- **Runtime-cache instead:** content that varies, is large, or is requested on demand is
  typically handled with a runtime caching strategy rather than being precached.

Precache the skeleton; let a runtime strategy handle the rest.

## Why content revisioning is the core problem

Precaching is only safe if the service worker can tell when a precached file has **changed**.
If you precache `/app.js` and later deploy a new `/app.js` at the same URL, the service worker
needs a signal that the content differs, or users keep the stale file.

Two ways to make change detectable:

- **Versioned URLs** (`/app.abc123.js`): the URL itself changes when content changes, so the
  precache entry is naturally new. Workbox treats a URL that already carries versioning
  information (such as a content hash) as its own revision.
- **A revision per entry:** pair each unversioned URL (like `/index.html`) with a content
  revision, so the cache refetches when the revision differs even though the URL is the same.

This bookkeeping is what a build-time **precache manifest** automates — maintaining it by hand
is error-prone, which is why precaching is usually delegated to a library.

## Workbox precaching in practice

Workbox's `workbox-precaching` module consumes a precache manifest (a list of
`{ url, revision }` entries, generated at build time) and handles the lifecycle for you:

- During `install`, it fetches and stores every listed asset.
- During `activate`, it removes entries from previous precaches that are no longer in the
  manifest, so old shell versions are cleaned up automatically.
- It serves precached responses from the cache, and refetches an entry when its revision
  changes.

```js
import { precacheAndRoute } from 'workbox-precaching';

// self.__WB_MANIFEST is injected at build time with { url, revision } entries.
precacheAndRoute(self.__WB_MANIFEST);
```

Workbox provides build tooling — `workbox-build`, the `workbox-webpack-plugin`, and the
`workbox-cli` — to generate that precache manifest from your actual build output, so the
list and revisions stay in sync with every deploy.

## Relationship to the HTTP cache

Precaching lives in the Cache Storage layer and is separate from the browser's HTTP cache.
The two can interact: a precache fetch may itself be served from the HTTP cache, which can
land a stale copy in your precache. Where that risk matters, use versioned URLs so each
version is a distinct request. Keep both layers' lifetimes in mind so they don't work against
each other.

## Practical checklist

- [ ] Precache only the minimal app shell; runtime-cache dynamic and large content.
- [ ] Prefer versioned (hashed) URLs so changed assets are distinct requests.
- [ ] For unversioned URLs (like `/index.html`), pair them with a content revision.
- [ ] Generate the precache manifest at build time with Workbox tooling; don't hand-maintain the list.
- [ ] Rely on Workbox to clean up superseded precaches on `activate`.
- [ ] Watch for HTTP-cache interactions that could precache a stale asset.