localStorage, sessionStorage, Cookies
Three Rooms, Three Lifetimes
LinkedIn Hook
"Should I use localStorage, sessionStorage, or a cookie?"
It's a question that looks trivial until the interviewer drills in: size limits, expiry rules, what gets sent to the server, what an XSS attacker can read, why
HttpOnlyexists, and why you should NEVER store a JWT in localStorage.These three storage APIs share the same goal and almost nothing else.
In this lesson you'll see a side-by-side comparison, the JSON-serialization trap that breaks beginner code, the
storageevent that lets tabs talk to each other, and the cookie attributes (HttpOnly,Secure,SameSite) that separate secure apps from compromised ones.Read the full lesson -> [link]
#JavaScript #WebStorage #WebSecurity #Frontend #InterviewPrep #Cookies #WebDevelopment
What You'll Learn
- The real differences between localStorage, sessionStorage, and cookies across size, expiry, and network behavior
- Why storage is strings-only — and the safe
JSON.stringify/JSON.parsewrapper pattern - Cookie attributes that matter for security:
HttpOnly,Secure,SameSite
Three Rooms in the Building
Think of these as three different types of storage rooms in a building. localStorage is a permanent locker — your stuff stays until you remove it. sessionStorage is a day locker — it's cleared when you leave (close the tab). Cookies are ID badges — they travel back and forth between you and the server on every request.
Comparison Table
| Feature | localStorage | sessionStorage | Cookies |
|---|---|---|---|
| Size limit | ~5-10 MB | ~5-10 MB | ~4 KB |
| Expiry | Never (manual delete) | Tab/window close | Set via expires/max-age |
| Sent to server | No | No | Yes, on every HTTP request |
| Scope | Same origin (all tabs) | Same origin + same tab | Same origin (configurable via path/domain) |
| API | setItem/getItem | setItem/getItem | document.cookie (string) |
| Accessible from | Client JS only | Client JS only | Client JS + Server (unless HttpOnly) |
| Storage type | Strings only | Strings only | Strings only |
localStorage and sessionStorage API
// SET
localStorage.setItem("username", "rakibul");
sessionStorage.setItem("tempToken", "abc123");
// GET
const name = localStorage.getItem("username"); // "rakibul"
const token = sessionStorage.getItem("tempToken"); // "abc123"
// REMOVE single item
localStorage.removeItem("username");
// CLEAR everything
localStorage.clear();
// Check length
console.log(localStorage.length);
// Iterate
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
console.log(key, localStorage.getItem(key));
}
JSON Serialization Requirement
Storage only accepts strings. You MUST serialize objects/arrays.
// WRONG — stores "[object Object]"
localStorage.setItem("user", { name: "Rakibul", age: 25 });
console.log(localStorage.getItem("user")); // "[object Object]" !!
// RIGHT — JSON serialize
const user = { name: "Rakibul", age: 25 };
localStorage.setItem("user", JSON.stringify(user));
const retrieved = JSON.parse(localStorage.getItem("user"));
console.log(retrieved.name); // "Rakibul"
// Safe retrieval with fallback
function getFromStorage(key, fallback = null) {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : fallback;
} catch (e) {
return fallback;
}
}
Storage Event (Cross-Tab Communication)
// This fires in OTHER tabs/windows of the same origin
// when localStorage changes — NOT in the tab that made the change
window.addEventListener("storage", function(e) {
console.log("Key changed:", e.key);
console.log("Old value:", e.oldValue);
console.log("New value:", e.newValue);
console.log("URL:", e.url);
});
// Tab A:
localStorage.setItem("theme", "dark");
// Tab B's storage listener fires with key="theme", newValue="dark"
Cookies
// SET a cookie
document.cookie = "username=rakibul; max-age=86400; path=/";
// max-age in seconds (86400 = 1 day)
// SET with expiry date
document.cookie = "token=abc; expires=Thu, 10 Apr 2027 00:00:00 UTC; path=/";
// READ all cookies (returns one string)
console.log(document.cookie); // "username=rakibul; token=abc"
// Parse cookies into an object
function getCookies() {
return document.cookie.split("; ").reduce((obj, pair) => {
const [key, val] = pair.split("=");
obj[key] = decodeURIComponent(val);
return obj;
}, {});
}
// DELETE a cookie (set max-age to 0)
document.cookie = "username=; max-age=0; path=/";
Cookie Attributes
Set-Cookie: session=abc123;
HttpOnly; // NOT accessible via JavaScript (XSS protection)
Secure; // only sent over HTTPS
SameSite=Strict; // not sent on cross-origin requests (CSRF protection)
Path=/; // available on all paths
Domain=.example.com; // available on subdomains
Max-Age=3600; // expires in 1 hour
When to use which:
- localStorage — user preferences, theme, language, cached data.
- sessionStorage — form draft data, single-session state, temp navigation data.
- Cookies — authentication tokens (with HttpOnly + Secure), server-side session IDs, tracking (with consent).
Common Mistakes
- Passing an object directly to
setItem— it gets coerced to"[object Object]". Always wrap withJSON.stringifyon the way in andJSON.parseon the way out. - Storing JWTs or auth tokens in
localStorage— any XSS-injected script can read them. PreferHttpOnly+Securecookies for session tokens. - Expecting the
storageevent to fire in the tab that made the change — it does not. It's a cross-tab sync signal for OTHER tabs on the same origin.
Interview Questions
Q: What is the difference between localStorage and sessionStorage?
Both share the same API and ~5-10MB limit. The key difference is persistence:
localStoragepersists until manually deleted (survives tab/browser close).sessionStorageis cleared when the tab or window is closed. Also,localStorageis shared across all tabs of the same origin, whilesessionStorageis scoped to a single tab.
Q: Are cookies sent to the server? Are localStorage/sessionStorage?
Yes, cookies are automatically included in every HTTP request to the matching domain. localStorage and sessionStorage are never sent to the server — they're purely client-side. This makes cookies useful for authentication but adds overhead to every request.
Q: What is HttpOnly and why is it important?
A cookie with the
HttpOnlyflag cannot be accessed via JavaScript (document.cookie). This protects against XSS attacks — even if an attacker injects a script, they can't steal HttpOnly cookies. Session tokens should always be HttpOnly.
Q: What is the size limit for localStorage? For cookies?
localStorage is typically 5-10 MB per origin (browser-dependent). Cookies are capped around 4 KB each, and browsers also limit the total number of cookies per domain (~50-180).
Q: When is sessionStorage cleared?
When the tab or window that owns it is closed. Refreshing the page keeps it; duplicating a tab in some browsers copies it; closing the tab wipes it.
Q: What does the SameSite cookie attribute do?
SameSite=Strictblocks the cookie from being sent on any cross-site request.SameSite=Lax(the modern default) allows top-level GET navigations but blocks cross-site POSTs — a CSRF mitigation.SameSite=None; Secureexplicitly opts into cross-site sending and requires HTTPS.
Quick Reference — Cheat Sheet
WEB STORAGE — QUICK MAP
localStorage sessionStorage Cookies
Size ~5-10 MB ~5-10 MB ~4 KB
Expiry never tab close Max-Age/Expires
Sent to server no no YES, every req
Scope all tabs single tab origin + path
API setItem/getItem same document.cookie
Values strings strings strings
Always serialize objects:
localStorage.setItem("u", JSON.stringify(user));
const user = JSON.parse(localStorage.getItem("u"));
Cross-tab sync:
window.addEventListener("storage", e => { /* e.key, e.newValue */ });
// fires in OTHER tabs, not the writer
Cookie security triple:
HttpOnly -> JS cannot read (XSS defense)
Secure -> HTTPS only
SameSite -> Strict | Lax (default) | None; Secure
Rule of thumb:
prefs/cache -> localStorage
draft state -> sessionStorage
auth tokens -> HttpOnly + Secure + SameSite cookie
Previous: Event Bubbling vs Capturing Next: requestAnimationFrame
This is Lesson 11.4 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.