localStorage vs sessionStorage vs cookies: which one to use?
The practical differences between localStorage, sessionStorage and cookies — capacity, lifetime, security and when to pick each one.
On this page
- The quick comparison
- What each one is
- localStorage
- sessionStorage
- Cookies
- Which one should you use?
- Performance and security notes
- FAQ
- When should I use a cookie instead of localStorage or sessionStorage?
- Why does localStorage survive a browser restart but sessionStorage does not?
- Is it safe to store a session token in localStorage?
- Are localStorage and sessionStorage synchronous?
- Summary
For data that lives in the browser, there are three classic options: localStorage, sessionStorage and cookies. In short: localStorage for data that must survive restarts and tabs, sessionStorage for temporary per-tab data, cookies for data the server needs on every request. This article compares them side by side.
The quick comparison
| Property | localStorage | sessionStorage | Cookies |
|---|---|---|---|
| Lifetime | Until cleared | Until the tab closes | Until expiry (or the session ends) |
| Scope | Per origin, shared across tabs | Per tab + origin | Per domain (+ path) |
| Sent to the server automatically | No | No | Yes, with every request |
| Capacity | ~5 MiB per origin | ~5 MiB per origin | ~4 KB per cookie |
| Accessible from JavaScript | Yes | Yes | Yes, unless HttpOnly |
| Blocking behavior | Synchronous | Synchronous | n/a (HTTP headers) |
MDN documents the storage limits: browsers allow up to roughly 5 MiB of local storage and 5 MiB of session storage per origin, and total browser storage is capped around 10 MiB. When the limit is reached, writes throw a QuotaExceededError. Cookies, by contrast, are commonly limited to about 4 KB per cookie and a few hundred cookies per domain.
What each one is
localStorage
localStorage is a key/value store that belongs to one origin — the scheme, host and port of the page. All documents with the same origin share the same localStorage area, and the data survives closing the browser entirely. It is the right place for preferences, saved themes or cached data you want to reuse on the next visit.
Keys and values are always strings. To store objects or arrays, convert them with JSON.stringify() first:
localStorage.setItem("theme", "dark");
const user = { name: "Ari" };
localStorage.setItem("user", JSON.stringify(user));
const saved = JSON.parse(localStorage.getItem("user"));
sessionStorage
sessionStorage is identical in API, but it is partitioned per browser tab. When the tab closes, everything stored in that tab's sessionStorage is destroyed. Refresh the same tab and the data is still there — open the same page in a new tab and it starts empty. Use it for state that only matters while the user is working on the page: draft input, a collapse state, a temporary filter.
sessionStorage.setItem("draft", "half-written comment");
Cookies
A cookie is a small piece of text the server sets with a Set-Cookie header, which the browser then sends back with every request to that domain. Unlike the storage APIs, cookies travel to the server automatically — that is their whole purpose: session IDs, authentication, tracking consent.
Cookies also have attributes that the storage APIs do not need: Secure (only send over HTTPS), HttpOnly (hide from JavaScript, for example to protect a session ID from cross-site scripting), SameSite (control when a cookie is sent on cross-site requests, which mitigates CSRF), and an expiry.
Which one should you use?
- Data the server must read on each request (session ID, auth token, tracking consent) → cookie.
- Data that must survive restarts and be shared across tabs of the same site (settings, cached UI state) →
localStorage. - Temporary data that should die with the tab (form drafts, one-off UI state) →
sessionStorage.
A common pattern: a session cookie for authentication, localStorage for user preferences, sessionStorage for in-tab draft state.
Performance and security notes
- Every cookie is sent with every request to its domain, so large or numerous cookies add bytes to every page load. Keep them small.
localStorageandsessionStorageare synchronous: a large read or write blocks the main thread and can make the page feel sluggish. Keep stored data small.- Never store sensitive data — passwords, access tokens, personal information — in
localStorage: any script running on the page can read it (a single XSS vulnerability exposes everything). Sensitive server-side values belong inHttpOnlycookies. - Storage APIs are per-origin, so data is readable by any script on the same origin. Cookies can be scoped further with
Pathand are protected from JavaScript whenHttpOnlyis set.
FAQ
When should I use a cookie instead of localStorage or sessionStorage?
Use a cookie when the server must read the data on every request, because cookies are sent automatically with every HTTP request to their domain, while localStorage and sessionStorage are never sent to the server. Authentication session IDs, "remember me" tokens and consent flags are typical cookie use cases; UI preferences and cached app state are not.
Why does localStorage survive a browser restart but sessionStorage does not?
The two APIs are partitioned differently. localStorage is scoped per origin and the data persists until the site or the user clears it, even across browser restarts and across all tabs of the same origin. sessionStorage is scoped per browser tab: closing the tab destroys everything stored in it, even if the same site is still open in another tab. Both APIs share the per-origin ~5 MiB quota and the ~10 MiB total browser storage cap.
Is it safe to store a session token in localStorage?
No. localStorage is readable by any JavaScript running on the same origin, so a single cross-site scripting (XSS) vulnerability lets an attacker read everything stored there and exfiltrate the token. Sensitive server-side values such as session IDs belong in cookies marked HttpOnly, which makes them invisible to JavaScript, and Secure so they are only sent over HTTPS, plus SameSite to mitigate cross-site request forgery (CSRF).
Are localStorage and sessionStorage synchronous?
Yes. Both APIs block the main thread during reads and writes, so storing or retrieving large values can make the page feel sluggish and harm Core Web Vitals. Cookies, by contrast, travel as HTTP headers and do not block JavaScript. Keep stored values small, and if you need to store more than a few hundred kilobytes, prefer the asynchronous IndexedDB API instead.
Summary
Use cookies for anything the server must see on every request, localStorage for preferences that outlive the browser session, and sessionStorage for throwaway per-tab state. All three are capped — keep values small, keep secrets out of localStorage, and prefer HttpOnly cookies for authentication data.
Sources
- MDN Web Docs — Web Storage API (developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API)
- MDN Web Docs — Using the Web Storage API (developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API)
- MDN Web Docs — Using HTTP cookies (developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies)
- MDN Web Docs — Browser storage quotas and eviction criteria (developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria)
Share this guide
Related guides
- How browser cookies work: a plain guide
What cookies are, how session and tracking cookies differ, and what 'accept all cookies' actually means.
- What is Server-Side Rendering (SSR)? How it works and when to use it
Server-side rendering generates the full HTML for a page on the server in response to a request — delivering a complete, crawlable page to the browser. Here's how SSR works, how it compares to client-side rendering, and when it makes sense for your project.
- What is a Service Worker? How it works and when to use it
A service worker is a JavaScript file the browser runs in the background, separate from the page. It sits between your app and the network and lets you cache assets, intercept requests, work offline, and receive push notifications. Here's how it works, what its lifecycle looks like, and when to reach for one.