localStorage vs cookies
localStorage vs cookies: storage limits, server access, and why session tokens still often belong in cookies.
Last updated
The short answer
localStorage is the right place for client-only data the server never needs to see — UI preferences, cached API responses, draft form state. Cookies remain the better fit for anything involving authentication, because they're the only mechanism sent automatically to the server and can be marked HttpOnly, which JavaScript-based storage can never do.
| Dimension | localStorage | Cookies |
|---|---|---|
| Storage limit | ~5-10MB per origin | ~4KB per cookie |
| Sent to server | Never, JS-only | Automatically, on every matching request |
| Accessible to JS | Always | Only if not marked HttpOnly |
| Expiry | Persists until explicitly cleared | Set expiry, or session-only |
| XSS exposure | Fully readable by any injected script | Hidden from JS if HttpOnly is set |
| Best for | Preferences, cached data, drafts | Auth tokens, session identifiers |
Choose localStorage when
- →You're storing UI state or preferences (theme, sidebar collapsed) that only your client-side JavaScript ever needs.
- →You need to cache a meaningfully sized payload — an API response, a draft document — well past the ~4KB a cookie allows.
- →The data has no business being sent to the server on every request, which is exactly what cookies do automatically.
Choose Cookies when
- →You're storing a session token or auth credential and want it marked HttpOnly so client-side JavaScript — including an XSS payload — can never read it.
- →The server needs the value automatically on every request without your frontend code manually attaching it.
- →You need fine control over expiry, domain and path scoping that the Set-Cookie mechanism gives you natively.
The catch nobody mentions
localStorage has no HttpOnly equivalent — anything stored there is readable by any script running on the page, including a malicious one injected via XSS. Storing a JWT or session token in localStorage is a common but genuine security mistake, since the moment an attacker gets script execution on your page, they get the token too.