Cookies vs localStorage vs sessionStorage
Three browser storage mechanisms. Different lifetimes, different security models, different use cases.
1 credit
Comparison
6 itemsMax size
Cookies: ~4KB each / localStorage: ~5-10MB / sessionStorage: ~5-10MBSent with requests
Cookies: yes (automatic) / Storage: no (manually attach)Lifetime
Cookies: until expiry / local: until cleared / session: until tab closesAccessible to JS
Cookies: only if not HttpOnly / Storage: alwaysCross-tab
Cookies: shared per origin / local: shared / session: tab-isolatedXSS read risk
Cookies (HttpOnly): no / Storage: yes — any injected script can readUse each for
- **HttpOnly, Secure cookies** — session/auth tokens. Server sets them, JS can't read them, immune to XSS theft.
- **localStorage** — user preferences, cached non-sensitive data, feature flags. Never tokens.
- **sessionStorage** — per-tab scratch data (multi-step form draft, pagination cursor).
- **IndexedDB** — if you need structured storage or >10MB. Async API, SQL-like queries.
Cookie attributes
6 itemsHttpOnly
JS can't access via document.cookie — blocks XSS token theft. ALWAYS set for auth cookies.Secure
Only sent over HTTPS. ALWAYS set in production.SameSite
`Lax` (default, safe), `Strict` (no cross-site at all), `None` (needs Secure + usually CSRF token)Domain
`.example.com` = send to all subdomains. Explicit `app.example.com` = that exact host.Path
Limit which URLs include the cookie. Usually `/`.Max-Age / Expires
How long before the cookie dies. Omit = session cookie (dies when browser closes).Anti-patterns
- Storing JWTs in localStorage — any XSS = account takeover. Use HttpOnly cookies.
- Storing PII (emails, phone) in localStorage — persists forever, even on shared machines.
- Relying on sessionStorage for auth — tab refresh = logged out. Use cookies.
- Setting cookies for every request — SameSite=Strict + fetch with `credentials: "omit"` = cookie absent anyway.