By Rahul — Google Frontend Engineer
Quick Comparison
Cookies
The oldest storage mechanism. Sent with EVERY HTTP request to the matching domain. This makes them ideal for authentication tokens but terrible for large data (you would send 4KB with every request).
Critical Cookie Attributes
- HttpOnly: JavaScript cannot access it. Prevents XSS from stealing tokens
- Secure: Only sent over HTTPS
- SameSite: Controls cross-site sending (Lax, Strict, None)
- Path: Cookie only sent for requests matching this path
- Domain: Which domains receive the cookie
localStorage
Persistent key-value storage. Data survives browser restarts. Shared across all tabs on the same domain.
sessionStorage
Same API as localStorage but scoped to the browser tab. Data is cleared when the tab closes. Each tab has its own isolated storage.
When to Use Which
- Auth tokens: HttpOnly cookies (NOT localStorage — XSS can steal localStorage)
- User preferences: localStorage (theme, language, notification settings)
- Form drafts: sessionStorage (auto-save current tab's form state)
- Shopping cart: localStorage (persist across sessions)
- Multi-step wizard state: sessionStorage (scoped to current flow)
Production Issues
- localStorage is synchronous: Reading 5MB of data blocks the main thread. Keep stored data small or use IndexedDB for large datasets
- Safari private mode: localStorage has a 0 byte quota in some older versions. Always wrap in try/catch
- Storage events:
window.addEventListener('storage', handler)fires in OTHER tabs when localStorage changes. Useful for cross-tab communication but easy to forget - Third-party cookie blocking: Safari ITP and Firefox ETP aggressively block third-party cookies. If your auth relies on cross-domain cookies, it may break
Summary
Cookies for auth tokens (HttpOnly, Secure). localStorage for persistent user preferences. sessionStorage for per-tab temporary state. Never store sensitive data in localStorage — it is accessible to any XSS attack.