LEARNING OBJECTIVES ⌵
- Inspect total available quota and origin storage usage using
navigator.storage.estimate(). - Understand the browser eviction lifecycle: "Best-Effort" (Temporary) vs "Persistent" storage.
- Request permanent storage guarantees using
navigator.storage.persist(). - Handle
QuotaExceededErrorexceptions gracefully in production web applications.
📖 The Mental Model & Story (Intuitive Foundation)
Imagine moving your personal belongings into a self-storage facility.
By default, the facility rents you a "Standby Storage Locker" (Best-Effort Storage). You can store hundreds of boxes for free. However, if the entire facility runs out of space, the building superintendent has the legal authority to discard your oldest boxes without asking your permission (LRU eviction—Least Recently Used).
If you run a mission-critical business with irreplaceable client files, you cannot afford to have the superintendent discard your boxes during a building space crunch.
You walk to the front desk and apply for a "Permanent Lease" (navigator.storage.persist()):
- The facility reviews your application. If you are a trusted tenant (an installed PWA, high site engagement, or granted permissions), they grant you Persistent Storage.
- Once marked Persistent, the browser will never silently evict or wipe your IndexedDB data, even if the device's hard drive is 99% full. Only the user themselves, by explicitly opening browser settings and clearing site data, can delete your database.
Technical Deep Dive & Specifications
Storage Quota Calculations
Modern browsers (Chromium, Firefox, WebKit) dynamically allocate storage quota based on the device's physical disk capacity:
+----------------------------------------------------------------------------------------------------+
| BROWSER STORAGE QUOTA MODELS |
+-------------------+------------------------------------+-------------------------------------------+
| Browser Engine | Origin Storage Quota | Storage Eviction Behavior |
+-------------------+------------------------------------+-------------------------------------------+
| **Chromium** | Up to ~60% of total free disk | Evicts origins by LRU (Least Recently |
| (Chrome, Edge) | space (shared across all origins) | Used) when disk space drops below safety |
+-------------------+------------------------------------+-------------------------------------------+
| **Firefox** | Up to 10% of total disk size per | Prompts user when approaching thresholds; |
| (Gecko) | origin; max group quota up to 50% | evicts temporary origins on disk pressure |
+-------------------+------------------------------------+-------------------------------------------+
| **Safari** | Starts at 1GB; prompts for more in | Wipes unvisited origins after 7 days of |
| (WebKit) | increments (iOS / macOS policies) | inactivity unless saved to Home Screen |
+-------------------+------------------------------------+-------------------------------------------+
The Storage API: Key Methods
// 1. Check current disk usage and total quota
const { usage, quota, usageDetails } = await navigator.storage.estimate();
// 2. Check if the current origin has persistent storage status
const isPersisted = await navigator.storage.persisted();
// 3. Request persistent storage permission
const granted = await navigator.storage.persist();
+-----------------------------------------------------------------------------+
| BEST-EFFORT vs PERSISTENT STORAGE |
+-------------------------------------+---------------------------------------+
| Best-Effort (Default) | Persistent Storage |
+-------------------------------------+---------------------------------------+
| • Subject to automatic LRU eviction | • Immune to automatic eviction |
| • Evicted under device disk pressure| • Data preserved until explicit user |
| • Ideal for caches, offline media | deletion in browser settings |
| • No user permission required | • Ideal for user drafts, offline CRM |
+-------------------------------------+---------------------------------------+
Browser Heuristics for Granting Persistence
When calling navigator.storage.persist(), Chromium-based browsers evaluate heuristic criteria before granting permission without prompting the user:
- Is the website bookmarked by the user?
- Has the web app been added to the Home Screen / installed as a PWA?
- Has the user granted Notifications or Geolocation permissions?
- Does the origin have high Site Engagement (frequent visits)?
💻 Interactive Code Playground
Starter Code
Save this file as storage-limits.html and open it in your browser.
Line-by-Line Code Breakdown
- Lines 82–97 (
await navigator.storage.estimate()): Queries the browser's storage manager for current byteusageand maximum availablequotaacross all origin storage APIs. - Lines 93–97 (
usageDetails): In Chromium browsers,usageDetailsprovides a granular byte breakdown specifically attributing storage across IndexedDB, Cache Storage, and Service Worker registrations. - Line 100 (
await navigator.storage.persisted()): Returns a boolean indicating whether the origin is currently protected from automated LRU eviction. - Line 118 (
await navigator.storage.persist()): Requests persistent storage status. Depending on the browser, this resolves silently based on site engagement heuristics or triggers a browser permission dialog. - Lines 143–145 (
const buffer = new Uint8Array(10 * 1024 * 1024)): Generates a 10-megabyte binary payload to demonstrate real-time quota updates.
Expected Browser Render Output
[03:15:00] 📊 Quota Report: Used 12.45 MB / 128.50 GB
[03:15:00] - IndexedDB: 12.10 MB
[03:15:00] - CacheStorage: 350.00 KB
[03:15:00] - ServiceWorkers: 0 Bytes
[03:15:05] 🛡️ Requesting persistent storage permission...
[03:15:05] 🎉 SUCCESS: Persistent storage granted by browser!
[03:15:10] 💾 Writing 10MB binary block to IndexedDB...
[03:15:11] ✅ 10MB block successfully committed.
[03:15:11] 📊 Quota Report: Used 22.45 MB / 128.50 GB🏋️ Hands-On Exercise
🎯 The Challenge: Graceful Quota Exhaustion Guard
Instructions:
- Create a function
safeSave(storeName, record)that wraps IndexedDB writes with a proactive quota check. - Before writing, query
navigator.storage.estimate():- If
(usage / quota) > 0.90(over 90% full), log a critical warning and reject the write with a custom warning: "Storage critical: Above 90% capacity. Purging recommended." - Otherwise, proceed with the write.
- If
- Catch any
QuotaExceededErrorthrown during insertion and log an emergency fallback message.
🏁 Starter Code Sandbox
⚠️ Common Pitfalls
- Assuming Quotas are Fixed at 50MB: Unlike old documentation that referenced legacy Web SQL quotas, modern IndexedDB quotas scale dynamically with available OS hard drive capacity.
- Ignoring WebKit's 7-Day Inactivity Rule: In Safari on iOS and macOS, temporary origin storage may be pruned if the user does not interact with the website for 7 consecutive days. Request persistent storage or prompt users to install your PWA to retain long-term offline data.
- Treating
navigator.storage.persist()as a Guarantee: Browsers may reject persistence requests if the user has never engaged with your domain. Always structure your application to function reliably even if persistence is denied.
💡 Pro Tips
- Implement LRU Cache Eviction in Userland: Build an index on
lastAccessedAttimestamp in your media cache. When storage reaches 80% capacity, run a cursor to delete the oldest 20% of media blobs before the browser triggers an origin eviction. - Prompt for Persistence During Key User Milestones: Instead of requesting
persist()on page load, trigger it when the user performs a high-intent action—such as creating an offline document, enabling offline sync, or installing your PWA.
📌 Key Takeaways
navigator.storage.estimate()provides real-time visibility into byteusageand allocatedquota.- By default, client storage is "Best-Effort", meaning the browser can purge it under low-disk conditions using an LRU eviction strategy.
navigator.storage.persist()requests persistent storage, protecting data from automated browser eviction.navigator.storage.persisted()checks the current persistence status of the origin.- Chromium grants persistence based on site engagement and installation heuristics, while WebKit enforces strict user-origin retention policies.
- --