DOMintermediate
localStorage, sessionStorage, and IndexedDB
The three main client-side storage APIs, ranging from simple synchronous key-value storage to a full asynchronous, transactional database in the browser.
Three storage APIs with very different capabilities.
localStorage is like a small notepad in your pocket — quick to jot a note on, but limited in space and only holds plain text. IndexedDB is like an actual filing room with labeled cabinets, folders, and a card-catalog index system for finding files by any attribute, capable of holding vastly more material, but requiring a bit more setup to use properly.
Key Concepts
1
localStorage 5-10 MB, synchronous, strings only,
persists until cleared
sessionStorage the same, cleared when the tab closes
IndexedDB hundreds of MB or more, asynchronous,
structured, indexed, transactional2
Web Storage is trivial to use and blocks the main thread.
localStorage.setItem('user', JSON.stringify(user));
const user = JSON.parse(localStorage.getItem('user') || 'null');3
Strings only, so everything is serialised both ways. Being synchronous means a large read blocks rendering —
a few hundred kilobytes parsed at startup is measurable.
4
IndexedDB is a real database in the browser.
const db = await openDB('app', 1, {
upgrade(db) {
const store = db.createObjectStore('orders', { keyPath: 'id' });
store.createIndex('by-date', 'date');
}
});5
await db.put('orders', order);
const recent = await db.getAllFromIndex('orders', 'by-date', range);6
Stores structured objects directly — no serialisation — with indexes, queries and transactions.
7
The raw API is famously awkward, which is why nearly everyone uses a wrapper such as idb. That is worth
saying: the API's reputation is deserved and the capability is not the problem.
idb
8
Choosing.
a preference, a flag, a token localStorage
state for this tab only sessionStorage
offline data, a large cache,
anything queried IndexedDB
cached HTTP responses the Cache API9
Everything is per origin. Different subdomains do not share storage, and nothing is sent to the server
automatically — unlike cookies.
10
Nothing expires on its own. An entry written a year ago is still there. Expiry is something you store
and check:
11
{ value, expiresAt: Date.now() + 3600000 }12
And every access can fail. Private browsing, blocked site data and quota limits all make these throw or
return nothing.
13
try { localStorage.setItem(k, v); } catch { /* quota or blocked */ }14
The page must work when storage is unavailable, which means treating it as a cache rather than as the source
of truth.
15
What the interviewer is probing.1. "What is the main performance problem with localStorage?" Probing: synchronicity. Stalls:
"It is small." Moves up: it is synchronous, so a large read or write blocks the main thread and
the UI.
16
2. "How do they differ in lifetime?" Probing: the scope. Stalls: "They are the same." *Moves
up:* localStorage persists until cleared; sessionStorage is per tab and dies with it.
17
3. "When do you need IndexedDB?" Probing: the third option. Stalls: "Never." Moves up:
larger structured data, binary blobs, indexes and asynchronous access — storage is a string
key-value store only.
18
4. "What happens in private browsing or with blocked cookies?" Probing: the failure mode.
Stalls: "It still works." Moves up: access can throw or silently return nothing, so every read
and write needs a try/catch and a working fallback.