Back to Browser Internals
Browser Internals
easy
mid

What are the differences between localStorage, sessionStorage, cookies, and IndexedDB?

Pick by need: cookies (sent to server, small, can be HttpOnly/Secure for auth); localStorage (persistent key-value, ~5MB, JS-only, sync API); sessionStorage (same but per-tab session); IndexedDB (large structured async storage, indexable, transactions). Tokens → HttpOnly cookies. UI prefs → localStorage. Big or structured data → IndexedDB.

4 min read·~12 min to think through

Four storage mechanisms, each with a different shape — knowing what trade-off you're paying for each is the interview point.

Cookies

  • Size: ~4KB per cookie, ~50–100 per domain.
  • Lifetime: until Expires/Max-Age; session if neither.
  • Sent automatically with every request to the domain → the only storage usable for server-side auth.
  • JS access: document.cookie (clunky) — but HttpOnly blocks JS access entirely (anti-XSS).
  • Security flags: Secure, HttpOnly, SameSite (Lax/Strict/None).
  • Use for: session tokens (HttpOnly + Secure + SameSite), CSRF tokens, server-readable preferences.

localStorage

  • Size: ~5MB per origin.
  • Lifetime: persistent until cleared.
  • Sync API — blocks the main thread; don't write large values.
  • String onlyJSON.stringify everything.
  • Scope: origin-wide, all tabs.
  • Not sent to server.
  • Use for: small UI prefs (theme, last-used filter), non-sensitive client-only data.
  • Don't use for: auth tokens (XSS-readable), large data, structured data with queries.

sessionStorage

  • Same API as localStorage but per-tab session — cleared when the tab closes.
  • Use for: wizard state mid-session, one-tab caches, scratch state.

IndexedDB

  • Size: large (often quota-based; can be hundreds of MB).
  • Async API — doesn't block the main thread.
  • Structured storage with indexes and transactions.
  • Real types — store objects, Blobs, Files.
  • Use for: offline-first apps (PWAs), large or structured data, queryable caches.
  • Cost: API is verbose; reach for Dexie or idb wrappers.

Cache Storage (bonus)

  • Tied to service workers; stores Request/Response pairs.
  • Use for: SW caching strategies (cache-first, etc.).

The decision matrix

NeedPick
Server-side authCookie (HttpOnly + Secure + SameSite)
Small UI prefslocalStorage
Per-tab session statesessionStorage
Large/structured/offlineIndexedDB
SW asset/response cacheCache Storage

Security notes

  • localStorage and sessionStorage are XSS-readable — never put auth tokens there. The "JWT in localStorage" pattern is widely criticized for this reason. HttpOnly cookies are the safer default.
  • Cookies need SameSite + Secure to mitigate CSRF and MITM.
  • IndexedDB is also XSS-readable — don't store secrets.

Performance notes

  • localStorage is synchronous — large reads/writes block. IndexedDB is async.
  • Quota-exceeded errors must be handled (try/catch).
  • storage event fires across tabs on localStorage changes — useful for tab sync (see [[how-would-you-keep-multiple-tabs-in-sync]]).

Interview framing

"Cookies are the only storage sent to the server, so auth tokens go there as HttpOnly + Secure + SameSite. localStorage is sync, ~5MB, persistent, origin-wide — fine for small UI prefs. sessionStorage is the same API but per-tab. IndexedDB is async, large, structured with indexes and transactions — the right answer for offline-first apps and big caches; use Dexie. All of localStorage, sessionStorage, and IndexedDB are XSS-readable, so secrets don't belong there."

Follow-up questions

  • Why are HttpOnly cookies safer for tokens than localStorage?
  • When would you reach for IndexedDB over localStorage?
  • What does SameSite=Lax/Strict/None do?
  • How do you sync state across tabs?

Common mistakes

  • JWT in localStorage exposed to XSS.
  • Writing big JSON blobs to localStorage and hitting quota.
  • Using localStorage where IndexedDB fits.
  • Forgetting SameSite/Secure on auth cookies.

Performance considerations

  • localStorage is sync — avoid large values. IndexedDB is async — use transactions, don't open per-op. Cookies bloat every request — keep them small.

Edge cases

  • Private/incognito mode quota limits.
  • Storage cleared mid-session.
  • Cross-tab updates via storage event.
  • Storage event doesn't fire in the same tab that wrote.

Real-world examples

  • Auth: HttpOnly session cookie.
  • Theme/UI: localStorage.
  • Email client offline cache: IndexedDB.
  • SW asset cache: Cache Storage.

Senior engineer discussion

Seniors pick storage by lifetime, size, sync/async, and security profile — and know XSS-readable storage is the wrong place for tokens. They reach for Dexie/idb instead of raw IndexedDB and respect SameSite/Secure on cookies.

Related questions