Build my web app

Offline-first: what to precache, what to cache on demand, and what to leave alone

A practical taxonomy of your site's files, storage quotas and eviction, versioning without stranding users, and designing an offline page that is actually useful.

"Works offline" is the promise that makes people take web apps seriously, and the promise most often broken by caching everything or nothing. This guide is about deciding, file by file, what your service worker should hold.

Three buckets

1. Precache: the shell

Files without which the app cannot render at all, cached during the service worker's install event:

Rule: if the total is over about 1–2 MB, you are precaching too much. Everything else can wait until it is requested.

2. Runtime cache: things people actually use

Cached the first time they are requested, with the strategy matching their volatility:

3. Never cache

Storage quota and eviction

Browsers grant an origin a share of free disk space — commonly hundreds of megabytes on phones, more on desktop — and may evict the whole origin's storage under pressure, oldest-unused first. Two implications:

Check usage with navigator.storage.estimate() and show a friendly message if you are near the limit rather than failing silently.

Versioning without stranding users

When you deploy, the old service worker keeps running until every tab of the old version is closed — a user with the app pinned open can stay on old code for days. Options, from gentle to forceful:

  1. Let it happen. Fine for content sites; they get the update next open.
  2. Show a "new version available — refresh" banner when a new worker is waiting (registration.waiting), and call skipWaiting() + reload on click. Best user experience for apps.
  3. skipWaiting() on install unconditionally. The new worker takes over immediately; pages loaded with old assets may break until refreshed. Only if your assets are hash-named so old pages keep working.

Whatever you choose, bump the cache name every deploy and delete old caches on activate, or storage fills with stale versions.

Designing the offline page

The generated offline.html is a start. Make it useful:

Offline forms

If users submit things (orders, comments, check-ins), the honest offline behaviour is to queue: store the submission in IndexedDB, show "Saved — will send when you're back online", and send it from the page when online fires. Background Sync automates the send on Chromium browsers but is not available on iOS, so build the page-side retry regardless.

Testing