Blog
4 min read

localStorage vs sessionStorage vs Cookies: Where Should You Store It?

Three ways to store data in the browser, with different lifetimes, sizes and security properties. What each one is for, why login tokens shouldn't go in localStorage, the size limits, and a simple rule for choosing.

Browsers give your app three main places to keep small bits of data on the user's device. They look similar but behave very differently — and choosing wrong for login tokens is a real security mistake.

The quick comparison

localStorage sessionStorage Cookies
Lasts Until cleared Until the tab closes Until its expiry date (or browser close)
Shared between tabs Yes (same site) No, per tab Yes
Sent to the server No No Yes, with every request
Size ~5–10 MB ~5 MB ~4 KB each
Readable by JavaScript Yes Yes Yes, unless HttpOnly
Best for Preferences, drafts Temporary per-tab state Login sessions

localStorage

Simple key–value storage that survives closing the browser:

localStorage.setItem('theme', 'dark')
localStorage.getItem('theme')          // "dark"
localStorage.removeItem('theme')

Values are always strings. For objects, use JSON:

localStorage.setItem('draft', JSON.stringify({ title, body }))
const draft = JSON.parse(localStorage.getItem('draft') ?? 'null')

Good for: theme (dark mode), dismissed banners, unsent drafts, UI preferences.

Not for: anything secret. Any JavaScript running on your page — including a third-party script or an XSS injection — can read all of it.

sessionStorage

The same API, but scoped to one tab and wiped when that tab closes. Opening the same site in a new tab starts empty.

Good for: multi-step form progress, "scroll position on this tab," one-off state you don't want leaking between tabs.

Cookies

Small pieces of data the server usually sets, which the browser automatically sends back with every request to that site. That's what makes them the natural fit for login sessions: the server sets a session cookie, and every subsequent request proves who you are. (What is a cookie?)

The security flags are the important part:

Flag Does
HttpOnly JavaScript cannot read the cookie — XSS can't steal it
Secure Only sent over HTTPS
SameSite=Lax / Strict Not sent on most cross-site requests — helps against CSRF
Max-Age / Expires How long it lasts

Where should login tokens go?

This is the question that matters. The safest common answer for web apps:

An HttpOnly, Secure, SameSite cookie.

Why not localStorage? Because if an attacker ever gets JavaScript onto your page — a compromised npm package, an XSS bug, a malicious browser extension — they can read every token in localStorage and use it from anywhere. An HttpOnly cookie can't be read by JavaScript at all.

Many AI-generated apps (and tutorials) store JWTs in localStorage because it's easy. It works, but it's the weaker choice. (Session cookies vs JWTs)

Auth libraries and services such as Supabase have their own defaults; read their docs on server-side/cookie-based sessions if you're rendering on the server.

Things that catch people out

  • Server-side rendering can't read localStorage. It only exists in the browser. Code like localStorage.getItem() running on the server crashes with "localStorage is not defined" — or causes hydration errors. Read it inside useEffect or after checking typeof window !== 'undefined'.
  • Private browsing may clear storage at the end of the session, and some browsers expire script-written storage after a period of no visits.
  • Storage can throw. When full, or when blocked by browser settings. Wrap writes in try/catch.
  • Cookies add weight to every request. Don't store large data in them.
  • Privacy rules. Non-essential cookies and similar storage may need consent in the EU. (Cookie consent banners)

The simple rule

  • Logged-in session → HttpOnly cookie.
  • Preference or draft that should survive restarts → localStorage.
  • Temporary state for one tab → sessionStorage.
  • Anything important → your database, not the browser.

EasySpawn runs your app's backend and database alongside the frontend, so sessions can live in secure server-set cookies and important data in Postgres, not the browser. See how it works or join the waitlist.

Related: What Is a Cookie? · Session Cookies vs JWTs · What Is a JWT? · XSS Explained

Keep reading