Section · 01
HTTP is stateless — and why that's a problem
Each HTTP request is independent. The server doesn’t remember you between requests. So how does a logged-in user stay logged in? How does a cart survive a refresh? With one of five storage mechanisms.
Cookies — small key/value pairs sent on every request to a domain
Sessions — server-side state identified by a session-id cookie
localStorage — bigger blob, JS-only, persists forever
sessionStorage — same, but cleared when the tab closes
IndexedDB — full client-side database for structured dataSection · 02
Cookies — small, automatic, persistent
A cookie is a small (~4KB) key/value pair the server sets on a response. The browser stores it and automatically sends it back on every subsequent request to that domain.
HTTP response:
Set-Cookie: session_id=abc123; Max-Age=3600; HttpOnly; Secure; SameSite=Lax; Path=/
HTTP request (next visit, automatic):
Cookie: session_id=abc123The flags that matter
HttpOnly — JavaScript can't read this cookie (defeats XSS theft)
Secure — only send over HTTPS
SameSite=Lax — don't send on cross-site requests (defeats CSRF for most cases)
Max-Age=3600 — expires in 3600 seconds; without this, expires when tab closes
Path=/ — which paths the cookie applies toEvery session cookie needs HttpOnly + Secure + SameSite. No exceptions. Three lines that prevent two entire classes of attack.
Section · 03
Sessions — cookies that point to server state
A session is the pattern of putting only an opaque session ID in the cookie and keeping the actual user data on the server (in memory, Redis, or a database).
Cookie — only the session ID (a random opaque string)
Example: session_id=abc123_random_unguessable
Server-side — a record keyed by that ID, containing:
- user_id
- permissions
- cart_id
- expires_atWhy use sessions instead of stuffing data into cookies directly? Cookies are sent on every request — so packing user state into them bloats every request. And client-side data can’t be trusted; server-side data can.
Stateless alternatives like JWT(JSON Web Tokens) put signed user data directly in a cookie or header. The server can verify the signature without a database lookup. Tradeoff: tokens can’t be revoked immediately (they stay valid until expiration).
Section · 04
localStorage — JS-readable, persistent
localStorage is a JavaScript-only key/value store that survives tabs, refreshes, and browser restarts. ~5-10MB depending on browser.
localStorage.setItem("theme", "dark");
localStorage.getItem("theme"); // "dark"
localStorage.removeItem("theme");
// JSON for objects
localStorage.setItem("user", JSON.stringify({ id: 1, name: "York" }));
const user = JSON.parse(localStorage.getItem("user"));Use for: theme/preferences, draft form data, non-sensitive UI state. Neveruse for: auth tokens. localStorage is readable by any JavaScript on the page, including malicious code injected via XSS. Cookies with HttpOnly cannot be read by JavaScript at all — that’s why they’re the right place for session IDs.
Section · 05
sessionStorage — same API, smaller lifetime
sessionStorage.setItem("wizard-step", "3");
sessionStorage.getItem("wizard-step");
// All sessionStorage data is cleared when the tab closes.Use sessionStorage when you want state to survive a refresh but not survive closing the tab — like a multi-step form wizard or a one-time onboarding flow.
Section · 06
IndexedDB — a database in the browser
IndexedDB is a real (NoSQL-ish) database built into the browser, with indexes, transactions, and the ability to store gigabytes. The API is awkward — most people use a wrapper like idb or Dexie.
When to reach for it: offline-first apps (PWAs), file editors that cache work in progress, anything where you need to keep meaningful amounts of structured data on the client. For 95% of web apps, you don’t need it.
Section · 07
Pick the right tool — a decision tree
Is it an auth token / session?
YES → HttpOnly cookie. Always. (Or server-side session keyed by an HttpOnly cookie.)
Does the server need to see it on every request?
YES → Cookie (with proper flags).
NO → next question.
Does it need to survive closing the tab?
YES → localStorage.
NO → sessionStorage.
Is it structured data, queryable, possibly huge?
YES → IndexedDB.
Is it sensitive in any way?
YES → server, not browser. Don't even start.Next lesson: the place server-side state actually lives — databases. Relational vs document, basic SQL, and the ORMs that put a nicer face on it.