Eviction and Persistence
Two storage modes
Section titled “Two storage modes”Every origin’s storage falls into one of two modes at any given time:
- Best-effort — the default mode. The browser may delete data from the origin without any user action if the device is running low on disk space.
- Persistent — the browser will not automatically evict the origin’s data. Data is only removed when the user explicitly clears it (via browser settings or your own code).
Most web applications run in best-effort mode, which is fine for non-critical caches and temporary data. If your app depends on cached data being available offline — for example, a PWA that must work with no connectivity — you should request persistent storage.
When does eviction happen?
Section titled “When does eviction happen?”Eviction is a browser-level decision triggered by storage pressure. The exact algorithm varies by browser, but the general process is:
- The device runs low on available disk space.
- The browser decides it needs to reclaim storage.
- It walks origins in roughly least-recently-used (LRU) order — origins that have not been visited recently are candidates first.
- Best-effort origins are cleared; persistent origins are left alone.
Eviction affects all storage for the origin simultaneously: Cache API, IndexedDB, and other quota-counted mechanisms are cleared together. You do not get to choose which data is kept.
How persist() protects data
Section titled “How persist() protects data”Calling navigator.storage.persist() sends a request to the browser asking it to move your origin into persistent mode. The browser may or may not grant this request:
const granted = await navigator.storage.persist();if (granted) { console.log('Storage is persistent — data is safe');} else { console.log('Best-effort only — browser may evict under pressure');}What influences the browser’s decision?
Section titled “What influences the browser’s decision?”Browsers use heuristics to decide whether to grant persistence. Common factors include:
- Whether the user has installed the PWA to their home screen or desktop.
- The user’s site engagement score — how frequently and recently they visit the site.
- Whether the user has explicitly granted a permission prompt (some browsers show one).
- Whether the origin has already been granted notifications or other powerful permissions.
There is no API to force the browser to return true. If it returns false, you can still use storage — it just may be evicted under pressure.
Checking current state
Section titled “Checking current state”Use navigator.storage.persisted() at app startup to check whether the origin is already persistent before deciding whether to request it or show a user-facing prompt:
const isAlreadyPersistent = await navigator.storage.persisted();
if (!isAlreadyPersistent) { // Optionally explain why you need it, then request const granted = await navigator.storage.persist(); if (!granted) { // Show a degraded-experience warning console.warn('Could not get persistent storage. Cached data may be lost.'); }}Practical guidance
Section titled “Practical guidance”- Do not assume
persist()will returntrue— always handle thefalsecase gracefully. - Call
persisted()first to avoid redundant prompts if the browser already granted persistence. - For apps where offline capability is critical, store enough diagnostic information in localStorage (which is harder to evict than Cache API in practice) to detect data loss on next load.
- Inform users when the app is running in best-effort mode so they understand the risk.