Skip to content

localStorage vs sessionStorage

The most important difference between the two stores is how long data lives:

localStorage

  • Data persists until it is explicitly removed with removeItem or clear, or the user clears browser data.
  • Closing all tabs, closing the browser, or restarting the machine does not remove the data.
  • This makes it suitable for preferences, themes, or cached values that should survive sessions (e.g., dark mode toggle, saved language choice).

sessionStorage

  • Data exists only for the lifetime of the browser tab (or window) in which it was created.
  • As soon as that tab is closed, the data is gone — no recovery.
  • Opening a new tab to the same URL starts a fresh, empty sessionStorage.
  • This makes it suitable for tab-local state that should not leak across tabs (e.g., a multi-step wizard’s current step, a one-time token, a temporary form draft).

Scope is where the two APIs differ most subtly:

// Tab A:
localStorage.setItem('demo:user', 'Ada');
// Tab B on the same origin sees 'Ada' immediately.
sessionStorage.setItem('demo:step', '2');
// Tab B has its OWN sessionStorage — it cannot see Tab A's 'step'.

There is one nuance: when a user opens a link with window.open() or Ctrl+click (which duplicates the tab), the new tab receives a copy of the parent tab’s sessionStorage at the moment it is opened. After that, the two stores are independent — changes in one do not propagate to the other.

Both stores are scoped to the origin: scheme + hostname + port.

URLOrigin
https://example.comhttps://example.com:443
https://app.example.comhttps://app.example.com:443 (different!)
http://example.comhttp://example.com:80 (different scheme!)
https://example.com:8080https://example.com:8080 (different port!)

So https://app.example.com and https://api.example.com each have their own completely separate localStorage even though they share the same registrable domain.

Run the snippet below to see both stores written and read back in the same page context.

Browser Storage
OptionBenefitCost
localStorageData persists and is shared across every tab of the same origin — good for long-lived preferencesA write from any tab affects every tab, risking a race condition if multiple tabs write at once
sessionStorageScoped to a single tab, reducing the risk of data leaking across tabs, and disappears when the tab closesMust be re-populated every time a new tab opens — not suitable for long-lived preferences
Sharing state via sessionStorage when duplicating a tabThe new tab gets the same context immediately on open (e.g. duplicating mid-form)It’s a one-time copy — the two tabs can’t sync afterward and may diverge
  • Assuming sessionStorage syncs across tabs like localStorage — each tab has its own separate sessionStorage; a write in Tab A is never visible in Tab B.
  • Storing an auth token in localStorage — because JavaScript can read it directly, an XSS hole on the origin can steal it easily, unlike an HttpOnly cookie that JS can’t touch.
  • Confusing a subdomain with the same origin — app.example.com and api.example.com always have separate localStorage, even though the registrable domain is the same.
You open Tab A and call sessionStorage.setItem("x", "1"). You then open Tab B to the same URL. What does sessionStorage.getItem("x") return in Tab B?
A user sets a dark-mode preference. Which store is most appropriate so the preference survives closing and reopening the browser?
Do https://shop.example.com and https://blog.example.com share the same localStorage?
When a user duplicates a tab (Ctrl+click a link), what happens to sessionStorage?