Reject / redirect
- Structured app data (drafts, entities) → IndexedDB, not Cache Storage
- Tiny string flags → memory / careful Web Storage
- File-shaped editor pipeline → consider OPFS
- Must-be-live money / auth → network-only (don’t fake success offline)
Versioning & stale content
- Named caches encode version (
static-v3)
activate deletes old names (origin-wide care)
- Nothing auto-expires — strategy + deploy plan own freshness
- Precache list matches this build’s hashed assets
CORS / opaque
- Prefer same-origin or CORS for assets you must cache reliably
add/addAll need 200-range; status 0 opaque won’t store via add
put of opaque is a conscious tradeoff (hard to debug/size)
Two cache layers
- SW Cache Storage ≠ HTTP cache (headers /
max-age)
- Revalidate path may still hit long-lived HTTP cache
- Headers + strategy designed to cooperate (or consciously diverge)
Will it stick?
- Quota shared with IndexedDB; catch
QuotaExceededError
- Best-effort eviction under disk pressure (LRU origins on Chromium/Firefox)
- Safari: script-writable storage can be capped after ~7 days without interaction (not for home-screen PWAs per WebKit)
navigator.storage.estimate() / optional persist()
- Runtime cache bloat bounded (images, unbounded URL sets)
Runtime hygiene
response.clone() when both putting and returning
- Match options intentional (query / method / Vary)
- Don’t use Cache Storage as a search index for many entities