How Does Browser Storage Quota Management Work?
Learn how browser storage quotas work across localStorage, IndexedDB, and Cache API, plus estimate() and persist() usage.
Expected Interview Answer
Browsers grant each origin a share of disk space for localStorage, IndexedDB, and Cache Storage that is bounded by a quota the browser computes from total free disk space, and when that origin’s usage approaches the limit the browser either rejects new writes with a QuotaExceededError or silently evicts data under storage pressure.
Each origin’s quota is not a fixed number; Chrome and Firefox typically allocate a percentage of total disk space, then divide it among origins, so the practical limit shifts as the disk fills up or empties. The `navigator.storage.estimate()` API lets code query current usage and the quota ceiling for the origin, returning `{ usage, quota }` in bytes so an app can proactively warn users or prune old cache entries before hitting the wall. Storage is split into best-effort and persistent buckets: best-effort storage can be evicted by the browser under disk pressure using an LRU-like policy across origins, while `navigator.storage.persist()` requests an exemption from that eviction, though the browser may still deny the request based on engagement heuristics. Different storage types (localStorage, IndexedDB, Cache API, Service Worker caches) all count against the same origin quota, so a service worker caching large assets can silently starve IndexedDB writes in the same origin.
- estimate() lets an app proactively monitor usage before hitting quota errors
- persist() protects critical offline data from eviction under disk pressure
- Understanding shared quota across storage types prevents silent write failures
- Proper quota handling keeps offline-first apps resilient on low-disk devices
AI Mentor Explanation
Quota management is like a stadium allocating locker space to each team based on how much total storage the venue has that season, not a fixed size carved in stone. A team can ask the groundskeeper how much locker space it has used and how much remains, similar to calling estimate() to see usage against quota. If the team wants guaranteed space that will not be reassigned when the venue gets crowded, it must formally request a reserved locker, just like calling persist() to avoid eviction. Bats, pads, and kit bags all share that one locker allotment, so overpacking one category can silently crowd out the others.
Step-by-Step Explanation
Step 1
Query current usage and quota
Call navigator.storage.estimate() to get { usage, quota } in bytes for the current origin.
Step 2
Compare usage against quota
Compute a ratio (usage / quota) to decide when to warn the user or start pruning old cached data.
Step 3
Request persistence for critical data
Call navigator.storage.persist() so offline-critical IndexedDB or cache data is exempt from best-effort eviction.
Step 4
Handle QuotaExceededError gracefully
Catch write failures on localStorage/IndexedDB and fall back to pruning, compressing, or notifying the user instead of crashing.
What Interviewer Expects
- Knowledge that quota is a dynamic percentage of free disk space, not a fixed number
- Familiarity with navigator.storage.estimate() and persist()
- Understanding that localStorage, IndexedDB, and Cache API share one origin quota
- Awareness of best-effort eviction versus persistent storage exemptions
Common Mistakes
- Assuming localStorage always has a fixed 5-10MB limit across all browsers and storage types
- Never checking navigator.storage.estimate() before writing large offline datasets
- Forgetting that Cache Storage used by a service worker eats into the same quota as IndexedDB
- Assuming persist() always succeeds instead of checking its boolean return value
Best Answer (HR Friendly)
“Browsers give each website a chunk of local storage space that grows or shrinks depending on how much free disk space the device has. You can ask the browser how much of that space you’ve used, and you can request that important offline data not get automatically cleared when the device runs low on space.”
Code Example
async function checkStorageHealth() {
if (!navigator.storage || !navigator.storage.estimate) return
const { usage, quota } = await navigator.storage.estimate()
const percentUsed = (usage / quota) * 100
if (percentUsed > 80) {
console.warn(`Storage at ${percentUsed.toFixed(1)}% — pruning old cache entries`)
await pruneOldCacheEntries()
}
const isPersisted = await navigator.storage.persisted()
if (!isPersisted) {
const granted = await navigator.storage.persist()
console.log(granted ? 'Storage persisted' : 'Persistence request denied')
}
}Follow-up Questions
- What eviction policy does a browser use when multiple origins compete for disk space?
- How does Cache Storage usage from a service worker affect IndexedDB quota?
- What heuristics do browsers use to decide whether to grant a persist() request?
- How would you design an offline-first app to gracefully handle QuotaExceededError?
MCQ Practice
1. What does navigator.storage.estimate() return?
estimate() returns { usage, quota } describing the current origin's consumption and ceiling.
2. What does navigator.storage.persist() do?
persist() asks the browser to protect the origin's storage from automatic eviction under disk pressure.
3. Which storage mechanisms typically share the same per-origin quota?
Browsers generally pool localStorage, IndexedDB, and Cache API usage into one origin-level quota.
Flash Cards
What determines an origin's storage quota? — A dynamic share of the device's total free disk space, not a fixed number.
How do you check current usage? — navigator.storage.estimate() returns { usage, quota } in bytes.
How do you protect data from eviction? — Call navigator.storage.persist() to request exemption from best-effort cleanup.
What happens when quota is exceeded? — Writes throw a QuotaExceededError, or the browser may evict older data first.