Web APIs Cheatsheet
Storage (localStorage, Cookies, IndexedDB)
Use this Web APIs reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
localStorage and sessionStorage
Both implement the
Storageinterface.localStoragepersists across sessions;sessionStorageis scoped to the browser tab.
// Set localStorage.setItem('key', 'value'); localStorage.setItem('obj', JSON.stringify({ a: 1 })); // Get localStorage.getItem('key'); // 'value' or null JSON.parse(localStorage.getItem('obj')); // { a: 1 } // Remove localStorage.removeItem('key'); localStorage.clear(); // remove all // Enumerate localStorage.length; // number of items localStorage.key(0); // key at index for (let i = 0; i < localStorage.length; i++) { const k = localStorage.key(i); console.log(k, localStorage.getItem(k)); } // or Object.entries(localStorage); // all [key, value] pairs
Storage API Quick Reference
| Method / Property | Description |
|---|---|
.setItem(key, value) | Store string value |
.getItem(key) | Retrieve string or null |
.removeItem(key) | Delete entry |
.clear() | Delete all entries |
.key(index) | Get key at numeric index |
.length | Number of stored items |
Storage Event
// Fires on OTHER tabs in the same origin (not the writing tab) window.addEventListener('storage', e => { e.key; // changed key (null if clear() called) e.oldValue; // previous value string e.newValue; // new value string (null if removed) e.url; // URL of the page that changed storage e.storageArea; // localStorage or sessionStorage reference });
Gotchas
- Only strings are stored. Always
JSON.stringify/JSON.parsefor objects.localStorageis synchronous and blocks the main thread on large reads/writes — prefer IndexedDB for bulk data.- Quota is ~5–10 MB per origin. Exceeds throw
DOMException: QuotaExceededError.- Not available in
file://origins or private browsing in some browsers.sessionStorageis NOT shared between tabs, even on the same origin.
IndexedDB
Asynchronous, transactional, key-value/object-store DB. Quota is typically 50%+ of disk. Supports complex queries via indexes.
Open and Upgrade
const request = indexedDB.open('MyDB', 2 /* version */); request.onupgradeneeded = e => { const db = e.target.result; const oldVersion = e.oldVersion; if (oldVersion < 1) { const store = db.createObjectStore('users', { keyPath: 'id', autoIncrement: true }); store.createIndex('by-email', 'email', { unique: true }); store.createIndex('by-name', 'name', { unique: false }); } if (oldVersion < 2) { db.createObjectStore('settings', { keyPath: 'key' }); } }; request.onsuccess = e => { const db = e.target.result; db.onversionchange = () => { db.close(); location.reload(); }; }; request.onerror = e => console.error(e.target.error);
CRUD Operations
// Helper: wrap IDB request in a Promise function idbRequest(req) { return new Promise((res, rej) => { req.onsuccess = () => res(req.result); req.onerror = () => rej(req.error); }); } // Add / Put const tx = db.transaction('users', 'readwrite'); const store = tx.objectStore('users'); const id = await idbRequest(store.add({ name: 'Alice', email: 'a@a.com' })); await idbRequest(store.put({ id, name: 'Alice B', email: 'a@a.com' })); // upsert await tx.done; // only available in idb library; else use tx.oncomplete // Get const tx2 = db.transaction('users', 'readonly'); const user = await idbRequest(tx2.objectStore('users').get(id)); // Get by index const byEmail = await idbRequest( tx2.objectStore('users').index('by-email').get('a@a.com') ); // Delete const tx3 = db.transaction('users', 'readwrite'); await idbRequest(tx3.objectStore('users').delete(id)); // Clear store await idbRequest(tx3.objectStore('users').clear());
Cursors and Range Queries
const tx = db.transaction('users', 'readonly'); const store = tx.objectStore('users'); const index = store.index('by-name'); // IDBKeyRange IDBKeyRange.only('Alice'); IDBKeyRange.lowerBound('A', false); // false = inclusive IDBKeyRange.upperBound('Z', true); // true = exclusive IDBKeyRange.bound('A', 'M', false, true); // Cursor const req = index.openCursor(IDBKeyRange.bound('A', 'M')); req.onsuccess = e => { const cursor = e.target.result; if (!cursor) return; // done console.log(cursor.key, cursor.value); cursor.continue(); // next // cursor.advance(2) — skip 2 // cursor.update({...cursor.value, active: true}) // cursor.delete() }; // getAll (no cursor overhead) const all = await idbRequest(store.getAll()); const range = await idbRequest(store.getAll(IDBKeyRange.lowerBound(10), 50 /* limit */)); const keys = await idbRequest(store.getAllKeys()); const count = await idbRequest(store.count());
Transactions
const tx = db.transaction(['users', 'settings'], 'readwrite'); tx.oncomplete = () => console.log('committed'); tx.onerror = e => console.error(e.target.error); tx.onabort = () => console.log('aborted'); tx.abort(); // manually roll back // Transactions auto-commit when no more requests are queued // Do NOT await non-IDB promises inside a transaction — it will close
idb Library (recommended wrapper)
import { openDB } from 'idb'; // npm install idb const db = await openDB('MyDB', 1, { upgrade(db) { db.createObjectStore('notes', { keyPath: 'id', autoIncrement: true }); }, }); await db.add('notes', { text: 'Hello', created: Date.now() }); const note = await db.get('notes', 1); const all = await db.getAll('notes'); await db.put('notes', { id: 1, text: 'Updated' }); await db.delete('notes', 1); // Transaction shorthand const tx = db.transaction('notes', 'readwrite'); await tx.store.add({ text: 'New' }); await tx.done;
Cache API (Service Worker)
// Open / create cache const cache = await caches.open('v1'); // Add requests await cache.add('/index.html'); await cache.addAll(['/style.css', '/app.js']); // Match const res = await cache.match('/index.html'); // Put (manual) const freshRes = await fetch('/data.json'); await cache.put('/data.json', freshRes.clone()); // Delete await cache.delete('/old.js'); // List all cache names const names = await caches.keys(); // Delete old caches await caches.delete('v0'); // Check if a URL is cached const hit = await caches.match('/style.css');
Storage Quota API
const { usage, quota } = await navigator.storage.estimate(); console.log(`${(usage / quota * 100).toFixed(1)}% used`); // Request persistent storage (won't be evicted automatically) const granted = await navigator.storage.persist(); const isPersisted = await navigator.storage.persisted();