Modern web apps use multiple browser storage mechanisms, each with different persistence, capacity, and privacy characteristics. Firefox implements all of them and has unique DevTools for inspecting each. This guide covers localStorage, sessionStorage, IndexedDB, cookies, Cache API, and Service Worker storage — and how to use Firefox's Storage Inspector to debug them.
The Storage Inspector
F12 → Storage tab (if not visible: DevTools gear → Enable Storage)
The Storage tab shows all storage for the current origin, organized by type:
- Local Storage / Session Storage
- IndexedDB
- Cookies
- Cache Storage (Service Worker caches)
- Extension Storage (WebExtensions)
localStorage and sessionStorage
localStorage persists indefinitely until cleared. Up to ~5MB per origin (browser-dependent, Firefox enforces this).
sessionStorage persists only for the current tab session — cleared when the tab closes. Each tab has its own sessionStorage, even for the same origin.
// localStorage
localStorage.setItem('theme', 'dark');
const theme = localStorage.getItem('theme');
localStorage.removeItem('theme');
localStorage.clear(); // clears all localStorage for this origin
// sessionStorage — same API, different scope
sessionStorage.setItem('currentStep', '3');
Firefox Storage Inspector: Select Local Storage → see all keys and values. Double-click a value to edit it inline. Right-click → Delete to remove. The filter bar at the top filters by key or value.
Privacy note: localStorage persists through browser restarts. In private browsing mode, localStorage is isolated and cleared when the private window closes.
IndexedDB
IndexedDB is a NoSQL object store for larger amounts of structured data (no size limit per spec, browsers give large amounts — Firefox typically allows several hundred MB).
// Open database
const request = indexedDB.open('AppDatabase', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
// Create object store with auto-incrementing key
const store = db.createObjectStore('tasks', { keyPath: 'id', autoIncrement: true });
store.createIndex('by_status', 'status', { unique: false });
};
request.onsuccess = (event) => {
const db = event.target.result;
// Add item
const tx = db.transaction('tasks', 'readwrite');
const store = tx.objectStore('tasks');
store.add({ title: 'Task 1', status: 'pending', created: Date.now() });
};
Promises wrapper (IndexedDB's callback API is unwieldy):
function openDB(name, version, upgradeFn) {
return new Promise((resolve, reject) => {
const req = indexedDB.open(name, version);
req.onupgradeneeded = e => upgradeFn(e.target.result, e);
req.onsuccess = e => resolve(e.target.result);
req.onerror = e => reject(e.target.error);
});
}
Or use the idb library: a Promise-based wrapper that makes IndexedDB much more usable.
Firefox Storage Inspector for IndexedDB: Expand the database → object store → see all records in a table. Add, edit, delete records. Search within the object store. Particularly useful for debugging cached data or offline-capable apps.
Cookies
Cookies are sent with HTTP requests (unlike localStorage/IndexedDB, which are JS-only).
// Reading cookies (all, as semicolon-separated string)
document.cookie
// Setting a cookie
document.cookie = 'user=alice; path=/; max-age=86400; Secure; SameSite=Strict';
// Deleting a cookie
document.cookie = 'user=; path=/; max-age=0';
For complex cookie management, the Cookie Store API provides an async, Promise-based interface:
await cookieStore.set({ name: 'user', value: 'alice', sameSite: 'strict' });
const cookie = await cookieStore.get('user');
await cookieStore.delete('user');
Firefox Cookie Inspector: shows all cookies with Name, Value, Domain, Path, Expiry, HttpOnly, Secure, SameSite. Double-click to edit. Especially useful for checking security attributes.
HttpOnly cookies: cookies with the HttpOnly flag can't be read by document.cookie — only by HTTP responses. The Storage Inspector can show them (since it reads them directly), but JavaScript can't.
Cache API (Service Worker Cache)
The Cache API stores HTTP response objects for offline use:
// Register cache
self.addEventListener('install', event => {
event.waitUntil(
caches.open('app-v1').then(cache =>
cache.addAll(['/index.html', '/styles.css', '/app.js'])
)
);
});
// Fetch from cache or network
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cached =>
cached || fetch(event.request)
)
);
});
Firefox Cache Inspector: Expand "Cache Storage" → see each named cache → see all cached responses with their URLs, status codes, and response headers. Delete individual entries or entire caches.
Storage Quotas
Each origin has a storage quota across all types (localStorage, IndexedDB, Cache API). Firefox's quota calculation:
- Temporary storage: ~10% of available disk space per origin
-
Persistent storage: requires explicit permission grant (
navigator.storage.persist())
Check quota usage:
const estimate = await navigator.storage.estimate();
console.log('Used:', estimate.usage, 'bytes');
console.log('Quota:', estimate.quota, 'bytes');
console.log('Usage breakdown:', estimate.usageDetails);
usageDetails breaks down usage by type: indexedDB, serviceWorkerRegistrations, caches, etc.
Request persistent storage (survives quota eviction pressure):
const persisted = await navigator.storage.persist();
console.log('Persistent storage:', persisted); // true if granted
Storage in Private Browsing
Private browsing (Private Windows) in Firefox:
- localStorage/sessionStorage: isolated and cleared when private window closes
- IndexedDB: available during private session, cleared on close
- Cookies: not persistent, cleared on close
- Cache API: works during session, cleared on close
Service workers are disabled entirely in Firefox private browsing.
OPFS (Origin Private File System)
The Origin Private File System API (Firefox 111+) provides file-system-like access to a private storage area:
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('data.bin', { create: true });
const writable = await fileHandle.createWritable();
await writable.write(new Uint8Array([1, 2, 3, 4]));
await writable.close();
// Read back
const file = await fileHandle.getFile();
const buffer = await file.arrayBuffer();
OPFS is separate from the public File System Access API — it's sandboxed to the origin and doesn't require user permission. Good for caching large binary data.
Top comments (0)