Skip to content

Eviction and Persistence

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.

Eviction is a browser-level decision triggered by storage pressure. The exact algorithm varies by browser, but the general process is:

  1. The device runs low on available disk space.
  2. The browser decides it needs to reclaim storage.
  3. It walks origins in roughly least-recently-used (LRU) order — origins that have not been visited recently are candidates first.
  4. 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.

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');
}

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.

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.');
}
}
  • Do not assume persist() will return true — always handle the false case 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.
What is the default storage mode for a new web origin?
When the browser evicts a best-effort origin due to storage pressure, what is cleared?
What does navigator.storage.persist() return if the browser denies the request?