📖 guide

Cookies, localStorage, and Session Storage: Which One When?

A comprehensive guide to browser storage mechanisms — understand cookies, localStorage, and sessionStorage, how they differ, when to use each, and the security implications of your choice.

Cookies, localStorage, and Session Storage: Which One When?

Websites need to remember things about you — your login status, preferences, shopping cart items. But browsers offer multiple ways to store that information: cookies, localStorage, and sessionStorage. Each has different characteristics, trade-offs, and use cases.


This guide explains how each storage mechanism works, when to use which, and the security implications of your choice. No exploit techniques — just literacy.


The Three Storage Mechanisms


Modern browsers provide three primary client-side storage options:


  • **Cookies** — Small text files automatically sent with every HTTP request
  • **localStorage** — Persistent key-value storage that never expires
  • **sessionStorage** — Temporary key-value storage cleared when the tab closes

  • All three store data on the user's device, but they differ in how they work, when they're accessible, and what they're best suited for.


    Related: Cookies vs. localStorage covers the basics in 4 minutes.


    Cookies: The Original Web Storage


    What they are:


    Cookies are small text files (max ~4KB per cookie) that servers send to browsers via HTTP headers. Browsers automatically attach cookies to every subsequent request to that domain.


    How they work:


    When a server responds to your request, it can include a Set-Cookie header:


    Set-Cookie: sessionId=abc123; Expires=Wed, 09 Sep 2026 10:18:14 GMT; Secure; HttpOnly


    Your browser stores this cookie and automatically sends it back on every future request to that domain:


    Cookie: sessionId=abc123


    Key characteristics:


  • **Automatic transmission**: Cookies travel with every HTTP request (even for images, CSS, scripts)
  • **Size limit**: ~4KB per cookie, ~180 cookies per domain
  • **Expiration**: Can be session cookies (deleted when browser closes) or persistent (expire at a set date)
  • **Domain scope**: Can be scoped to specific domains and subdomains
  • **Path scope**: Can be limited to specific URL paths

  • Security attributes:


  • **Secure**: Cookie only sent over HTTPS
  • **HttpOnly**: Cookie inaccessible to JavaScript (prevents XSS attacks from stealing it)
  • **SameSite**: Controls whether cookies are sent with cross-site requests (helps prevent CSRF attacks)

  • When to use cookies:


  • **Authentication/session management**: Cookies automatically attach to requests, making them ideal for maintaining login state
  • **Server-side needs**: When the server needs to know something on every request
  • **Cross-domain tracking**: Third-party cookies (though increasingly restricted by browsers)

  • When NOT to use cookies:


  • **Large data storage**: Size limit is too small
  • **Client-side-only data**: No need to send data to the server on every request (adds overhead)
  • **Frequent writes**: Every cookie change triggers a new HTTP header

  • Learn more about how browsers connect to servers: The Journey of a URL


    localStorage: Persistent Client-Side Storage


    What it is:


    localStorage is a JavaScript API that stores key-value pairs in the browser with no expiration. Data persists even when the browser is closed and reopened.


    How it works:


    JavaScript code explicitly reads and writes to localStorage:


    // Store data

    localStorage.setItem('theme', 'dark');

    localStorage.setItem('username', 'alex');


    // Retrieve data

    const theme = localStorage.getItem('theme'); // 'dark'


    // Remove data

    localStorage.removeItem('theme');


    // Clear all

    localStorage.clear();


    Key characteristics:


  • **Never transmitted**: Data stays in the browser unless you explicitly send it via JavaScript
  • **Size limit**: Typically 5-10MB per origin (varies by browser)
  • **No expiration**: Data persists indefinitely until explicitly deleted or user clears browser data
  • **Origin-scoped**: Only accessible by the same protocol, domain, and port (`https://example.com` ≠ `http://example.com`)
  • **Synchronous API**: Blocking operations (can slow down page load if overused)

  • When to use localStorage:


  • **User preferences**: Theme, language, UI settings
  • **Draft content**: Auto-saving form data, editor content
  • **Client-side caching**: Reduce server requests by caching data locally
  • **Offline-first apps**: Store data that doesn't need server synchronization
  • **Large datasets**: More storage capacity than cookies

  • When NOT to use localStorage:


  • **Sensitive data**: localStorage is accessible to any JavaScript on the page (including third-party scripts)
  • **Authentication tokens**: Vulnerable to XSS attacks (use HttpOnly cookies instead)
  • **Data needed by server**: No automatic transmission (unlike cookies)
  • **Truly private data**: User can view localStorage via browser DevTools

  • Security note:


    Any JavaScript running on your page can read localStorage. If an attacker injects malicious script (XSS attack), they can steal everything in localStorage. Never store authentication tokens or sensitive data here unless absolutely necessary and with additional safeguards.


    Related: How Web Tracking Works explains browser-based data collection.


    sessionStorage: Temporary Tab-Specific Storage


    What it is:


    sessionStorage is nearly identical to localStorage, but data is scoped to a single browser tab and is cleared when that tab closes.


    How it works:


    The API is identical to localStorage:


    // Store data

    sessionStorage.setItem('currentStep', '3');


    // Retrieve data

    const step = sessionStorage.getItem('currentStep');


    // Remove data

    sessionStorage.removeItem('currentStep');


    Key characteristics:


  • **Tab-scoped**: Each tab has its own independent sessionStorage
  • **Never transmitted**: Like localStorage, stays in the browser
  • **Size limit**: Same as localStorage (~5-10MB)
  • **Session lifetime**: Cleared when the tab closes (not when navigating within the tab)
  • **Not shared between tabs**: Opening the same site in two tabs creates two separate sessionStorage instances

  • When to use sessionStorage:


  • **Multi-step forms**: Store progress through a wizard without persisting after the tab closes
  • **Temporary UI state**: Current page of pagination, expanded/collapsed sections
  • **Single-session workflows**: Data that should not persist across visits
  • **Tab-specific state**: When you want isolation between tabs of the same site

  • When NOT to use sessionStorage:


  • **Data that should persist**: Use localStorage or cookies instead
  • **Data needed across tabs**: sessionStorage doesn't share between tabs
  • **Sensitive authentication**: Same XSS vulnerability as localStorage

  • Gotcha:


    "Session" doesn't mean "until the user logs out" — it means "until the tab closes." Navigating to other pages within the same tab does NOT clear sessionStorage.


    Side-by-Side Comparison


    | Feature | Cookies | localStorage | sessionStorage |

    |---------|---------|--------------|----------------|

    | Max size | ~4KB per cookie | ~5-10MB | ~5-10MB |

    | Sent to server | Yes, automatically | No | No |

    | Accessible via JS | Yes (unless HttpOnly) | Yes | Yes |

    | Lifespan | Set by server or session | Until explicitly deleted | Until tab closes |

    | Scope | Domain + path | Origin (protocol + domain + port) | Origin + tab |

    | Security flags | Secure, HttpOnly, SameSite | None (JS-controlled) | None (JS-controlled) |

    | Best for | Authentication, server needs | Preferences, offline cache | Temp UI state, multi-step forms |


    When to Use Which: Decision Tree


    Use cookies when:


  • The server needs the data on every request (authentication tokens, session IDs)
  • You need HttpOnly protection against XSS
  • You need fine-grained control over expiration, domain, and path

  • Use localStorage when:


  • Data should persist across sessions
  • The server doesn't need automatic access
  • You need more than ~4KB of storage
  • Data is user preferences or client-side cache

  • Use sessionStorage when:


  • Data should NOT persist after the tab closes
  • You need tab-specific isolation
  • Temporary workflow state (wizards, multi-step processes)

  • Use none (just in-memory JavaScript variables) when:


  • Data only matters during the current page load
  • No need to survive page refresh

  • Related concepts: CORS in Plain Language explains cross-origin security for storage and requests.


    Security Considerations


    XSS (Cross-Site Scripting) Attacks


    Both localStorage and sessionStorage are vulnerable to XSS. If an attacker injects malicious JavaScript into your page, they can read all stored data.


    Mitigation:


  • Never store sensitive data (passwords, credit cards) in localStorage or sessionStorage
  • Use HttpOnly cookies for authentication tokens
  • Sanitize user input to prevent XSS
  • Implement Content Security Policy (CSP)

  • CSRF (Cross-Site Request Forgery) Attacks


    Cookies automatically attach to requests, which makes them vulnerable to CSRF attacks — malicious sites can trigger authenticated requests to another domain.


    Mitigation:


  • Use `SameSite` cookie attribute (`SameSite=Strict` or `SameSite=Lax`)
  • Implement CSRF tokens for sensitive actions
  • Verify request origin on the server

  • Third-Party Cookie Tracking


    Third-party cookies (from domains you didn't visit) enable cross-site tracking. Advertisers use them to follow you around the web.


    What's changing:


    Modern browsers are phasing out third-party cookies. Firefox and Safari block them by default. Chrome is in transition. This breaks legacy tracking but improves privacy.


    Related reading: How Web Tracking Works


    Practical Examples


    Example 1: Authentication (Use Cookies)


    Why cookies:


    The server needs to verify your identity on every request. Cookies automatically attach, and HttpOnly prevents JavaScript theft.


    // Server sets cookie (Node.js/Express example)

    res.cookie('sessionId', 'abc123', {

    httpOnly: true, // JavaScript can't read it

    secure: true, // HTTPS only

    sameSite: 'strict',

    maxAge: 86400000 // 24 hours

    });


    Never do this:


    // DON'T store auth tokens in localStorage

    localStorage.setItem('authToken', 'sensitive-token'); // Vulnerable to XSS!


    Example 2: Dark Mode Toggle (Use localStorage)


    Why localStorage:


    User preference that should persist across sessions. Server doesn't need it.


    // Save preference

    function setTheme(theme) {

    localStorage.setItem('theme', theme);

    document.body.className = theme;

    }


    // Load preference on page load

    const savedTheme = localStorage.getItem('theme') || 'light';

    document.body.className = savedTheme;


    Example 3: Multi-Step Form (Use sessionStorage)


    Why sessionStorage:


    Temporary workflow state that shouldn't persist after the tab closes. Don't want users resuming abandoned forms weeks later with stale data.


    // Save progress

    function saveFormProgress(step, data) {

    sessionStorage.setItem('formStep', step);

    sessionStorage.setItem('formData', JSON.stringify(data));

    }


    // Load progress

    function loadFormProgress() {

    const step = sessionStorage.getItem('formStep');

    const data = JSON.parse(sessionStorage.getItem('formData') || '{}');

    return { step, data };

    }


    // Clear on submission

    function submitForm() {

    // ... submit logic

    sessionStorage.removeItem('formStep');

    sessionStorage.removeItem('formData');

    }


    Example 4: Shopping Cart (Use… It Depends)


    Option 1: localStorage (guest users)


    Cart persists even if they close the browser and come back later.


    localStorage.setItem('cart', JSON.stringify(cartItems));


    Option 2: Server-side + cookies (logged-in users)


    Cart stored on server, cookie authenticates user. Cart syncs across devices.


    Option 3: Hybrid approach


    Use localStorage for guests, sync to server when they log in.


    Browser Support and Compatibility


    All modern browsers support cookies, localStorage, and sessionStorage:


  • Chrome, Edge, Firefox, Safari: Full support
  • Internet Explorer: Partial support (IE 8+ for localStorage/sessionStorage)
  • Mobile browsers: Full support

  • Gotchas:


  • **Private/Incognito mode**: localStorage and sessionStorage may be cleared when the session ends
  • **Storage quota**: Browsers may refuse writes if storage is full (catch `QuotaExceededError`)
  • **Same-origin policy**: Strict origin matching (`https://example.com` can't read `http://example.com` storage)

  • The Takeaway


    Cookies, localStorage, and sessionStorage serve different purposes:


  • **Cookies** automatically travel with requests — ideal for authentication but limited size and privacy concerns
  • **localStorage** persists indefinitely — great for user preferences and offline caching
  • **sessionStorage** is tab-specific and temporary — perfect for transient workflow state

  • Choose based on:

  • Does the server need it? → Cookies
  • Should it persist across sessions? → localStorage
  • Should it clear when the tab closes? → sessionStorage

  • Security matters: Use HttpOnly cookies for auth, never store sensitive data in localStorage/sessionStorage, and always sanitize input to prevent XSS.




    Related Reading:


  • [Cookies vs. localStorage](/bits/cookies-vs-localstorage) — interactive 4-minute comparison
  • [How Web Tracking Works](/bits/web-tracking-basics) — understanding third-party cookies and tracking
  • [CORS in Plain Language](/bits/cors-plain-language) — cross-origin security for requests and storage
  • [The Journey of a URL](/bits/url-journey) — see how cookies travel with HTTP requests
  • [What That Padlock Really Means](/bits/https-padlock) — HTTPS security including Secure cookie attribute



  • *This post is part of Hacking Bits, where we explain how everyday technology works — one bit at a time.*


    Related Posts