Home/Learn/JavaScript & TypeScript/Browser Storage — localStorage, Cookies and IndexedDB

Browser Storage — localStorage, Cookies and IndexedDB

Intermediate
The Browser

Four options with different lifetimes, sizes and security properties. The choice that matters most is where an auth token goes, and the answer is usually not localStorage.

Overview

localStorage is the one everybody reaches for: synchronous, simple, about 5MB, and it survives a browser restart. sessionStorage is the same but scoped to one tab. Cookies are small and are sent with every request to the origin, which is what makes them useful for authentication and annoying for anything else. IndexedDB is the real database — asynchronous, large, structured. The security point worth internalising early: anything in localStorage is readable by any JavaScript on the page, so a single XSS gives away every token stored there.

localStorage and sessionStorage

Same API, different lifetime. Both store strings only, and both can throw.

Strings only, and it can throw
localStorage.setItem('theme', 'dark')
localStorage.getItem('theme')          // 'dark', or null
localStorage.removeItem('theme')

// Objects must be serialised
localStorage.setItem('user', JSON.stringify(user))
const user = JSON.parse(localStorage.getItem('user') ?? 'null')

// It can throw — private mode, quota full, storage blocked
function safeSet(key, value) {
  try { localStorage.setItem(key, JSON.stringify(value)) }
  catch { /* quota or blocked — carry on without persisting */ }
}

// sessionStorage: identical API, cleared when the tab closes,
// and not shared between tabs even on the same site.

// Cross-tab sync comes free with the storage event:
window.addEventListener('storage', e => {
  if (e.key === 'theme') applyTheme(e.newValue)   // fires in OTHER tabs
})

Cookies, and Where Tokens Belong

The security comparison that decides your auth design.

Why a token in localStorage is an XSS liability
// localStorage: readable by ANY script on the page.
// One XSS -> the attacker has your token.
localStorage.setItem('token', jwt)          // convenient, and exposed

// httpOnly cookie: not readable by JavaScript at all.
// Set by the server:
Set-Cookie: session=abc;
            HttpOnly;        // JS cannot read it — blocks XSS theft
            Secure;          // HTTPS only
            SameSite=Lax;    // blocks most CSRF
            Max-Age=86400

// The trade-off:
//   localStorage  -> vulnerable to XSS, immune to CSRF, easy cross-origin
//   httpOnly cookie -> immune to XSS theft, needs CSRF protection,
//                      needs credentials:'include' cross-origin

// For a browser app talking to your own API, httpOnly + SameSite
// is the stronger default.

IndexedDB and the Cache API

When you need more than a few megabytes or want to query structured data offline.

IndexedDB for data, Cache API for responses
// IndexedDB — async, large (hundreds of MB), indexed, transactional.
// The raw API is verbose; in practice use a wrapper such as idb.
import { openDB } from 'idb'

const db = await openDB('aicancode', 1, {
  upgrade(db) {
    const store = db.createObjectStore('submissions', { keyPath: 'id' })
    store.createIndex('by-problem', 'problemId')
  },
})
await db.put('submissions', submission)
await db.getAllFromIndex('submissions', 'by-problem', problemId)

// Cache API — for HTTP responses, used by service workers
const cache = await caches.open('v1')
await cache.addAll(['/offline.html', '/styles.css'])

Key Points to Remember

  • 1localStorage persists across restarts, sessionStorage clears with the tab, and both store strings only
  • 2localStorage access can throw in private mode or when the quota is full — always wrap it in try/catch
  • 3Anything in localStorage is readable by any script on the page, so one XSS exposes every stored token
  • 4An httpOnly, Secure, SameSite cookie cannot be read by JavaScript, which is the stronger default for auth
  • 5The storage event fires in other tabs, giving cross-tab sync for free; IndexedDB is the option for large structured data

Interview Questions

Sign in to ask Aria
1

What is the difference between localStorage and sessionStorage?

Easy
2

Why is storing a JWT in localStorage considered risky, and what is the alternative?

Hard
3

How would you keep two open tabs of your app in sync when a setting changes?

Medium

Ask Aria about Browser Storage — localStorage, Cookies and IndexedDB

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…