Web Storage
Browser APIs for storing key-value data on the client, without needing a server round-trip. All stored values are strings — objects must be serialized (see json) before storing.
localStorage
Persists data with no expiration — it survives page reloads, browser restarts, even the computer restarting. Scoped per origin (protocol + domain + port).
localStorage.setItem("theme", "dark");
console.log(localStorage.getItem("theme")); // "dark"
localStorage.removeItem("theme");
console.log(localStorage.getItem("theme")); // null — key no longer exists
localStorage.setItem("lastVisit", "count"); // overwritten by the next line
localStorage.clear(); // wipes everything for this origin
// Storing objects requires JSON serialization
const user = { name: "Ada", theme: "dark" };
localStorage.setItem("user", JSON.stringify(user));
const stored = JSON.parse(localStorage.getItem("user"));
console.log(stored.name); // "Ada"
localStorage.getItem("nonexistent"); // null, NOT undefined — check for this explicitly
sessionStorage
Same API as localStorage, but scoped to a single tab’s session — cleared when that tab is closed. Not shared across tabs, even for the same site.
sessionStorage.setItem("formDraft", "unsaved changes");
console.log(sessionStorage.getItem("formDraft")); // "unsaved changes"
// Closing this tab (or the browser) clears it; opening the same site in
// a NEW tab starts with an empty sessionStorage.
localStorage vs sessionStorage vs Cookies
// localStorage: ~5-10MB, persists indefinitely, JS-only, never sent to the server
// sessionStorage: ~5-10MB, persists per-tab until closed, JS-only, never sent to the server
// cookies: ~4KB, configurable expiry, sent with EVERY matching HTTP request
Cookies are set/read differently — via document.cookie (a single string you parse manually) or, more commonly, by the server via the Set-Cookie response header.
document.cookie = "theme=dark; max-age=3600; path=/"; // expires in 1 hour
console.log(document.cookie); // "theme=dark" (plus any other cookies, semicolon-separated)
// Deleting a cookie: set it with a past expiration
document.cookie = "theme=; max-age=0; path=/";
Listening for changes across tabs
localStorage fires a storage event in other tabs/windows (not the one that made the change) — useful for syncing state across open tabs.
window.addEventListener("storage", (event) => {
console.log(
`"${event.key}" changed from "${event.oldValue}" to "${event.newValue}"`
);
});
// Only fires in OTHER tabs on the same origin when localStorage changes here —
// the tab that made the change does not receive its own event.
When to use which
localStorage— user preferences (theme, language), auth tokens for non-sensitive use cases, caching data between visits.sessionStorage— per-tab temporary state (multi-step form drafts, wizard progress).- Cookies — anything the server needs to read on each request (session IDs, CSRF tokens), or when you need fine-grained expiration/security flags (
HttpOnly,Secure,SameSite).