Client-side storage
Choose between cookies, localStorage, sessionStorage, and IndexedDB by lifetime, size, and exposure.

WHAT YOU WILL BE ABLE TO DO
Learning outcomes
- Explain client-side storage in plain language.
- Connect the behavior to the underlying browser or framework model.
- Implement the core pattern and reason through edge cases.
- Answer common follow-ups without relying on memorized phrases.
01Explain it simply
The browser gives pages several places to persist data on the user's device: cookies (sent automatically with matching requests), localStorage and sessionStorage (synchronous key-value strings scoped to an origin), and IndexedDB (an asynchronous transactional database for structured or large data).
One-line definition: Choose between cookies, localStorage, sessionStorage, and IndexedDB by lifetime, size, and exposure.
02Mental model
Pick storage by three questions: does it need to travel to the server automatically (cookie), does it need to survive tab close and stay simple key-value text (localStorage), is it scoped to one tab's lifetime (sessionStorage), or does it need to hold structured, large, or queryable data without blocking the main thread (IndexedDB).
03Step by step
- Decide whether the server needs to see the value on every request.
- Decide whether the data must survive closing the browser.
- Check the size and structure — localStorage is capped and string-only.
- Use IndexedDB for anything large, binary, or requiring queries/transactions.
- Treat everything readable by JavaScript as exposed to any script that runs in that origin.
04Working example
localStorage.setItem('theme', 'dark');sessionStorage.setItem('draftId', '42');
const db = await indexedDB.open('cache-store', 1);// localStorage/sessionStorage APIs are synchronous and block the main thread;// IndexedDB is asynchronous and suited to larger data.localStorage persists across sessions and tabs for the same origin; sessionStorage is isolated per tab and cleared when that tab closes; IndexedDB is the only one of the three built for larger, structured, or binary data without blocking rendering.
05Where it is used
- Remembering UI preferences such as theme or layout
- Offline-capable apps caching structured records
- Per-tab draft or wizard state
- Session cookies for authentication
06Common mistakes
- Storing sensitive tokens in localStorage where any injected script can read them
- Assuming localStorage has no size limit — it's typically capped around 5-10MB per origin
- Using synchronous localStorage for large data and janking the main thread
- Forgetting that sessionStorage does not survive opening a link in a new tab
07Interview answer
Justify the choice by exposure and lifetime, not habit — naming the XSS exposure of script-readable storage versus the CSRF exposure of automatically-sent cookies shows you understand the actual trade-off.
Why might an HttpOnly cookie be safer than localStorage for a session token, even though the browser still sends it automatically?
HttpOnly makes the cookie's value unreadable to any JavaScript running on the page, so a successful XSS injection can't directly exfiltrate it, whereas localStorage is plain-text readable by any script in that origin.
DDConcept deep dives
Deep dive 1
Match storage to lifetime and audience
Cookies travel to the server automatically and are the only mechanism that does so without extra code, making them the natural fit for session identifiers. localStorage and sessionStorage are purely client-side and differ only in lifetime — tab-scoped versus persistent. IndexedDB adds structure, size, and asynchronous access on top of that same client-only scope.
- A cookie's automatic transmission is a feature for auth and a liability for CSRF.
- sessionStorage disappearing on tab close is often exactly the desired behavior for transient state.
- IndexedDB is the only option suited to large or binary data.
Deep dive 2
Everything script-readable is exposed to injected script
localStorage, sessionStorage, and non-HttpOnly cookies are all readable by any JavaScript executing in that origin, including a successful XSS payload. This is a structural property of the platform, not a misconfiguration — the mitigation is reducing what's stored there and for how long, not assuming a particular API is inherently safe.
- HttpOnly is the one attribute that hides a cookie's value from JavaScript entirely.
- Reducing token lifetime shrinks the exposure window regardless of storage choice.
- Treat client storage as readable by anything running in the page, not just your own code.
Deep dive 3
Storage is partitioned by exact origin
Scheme, host, and port must all match for two contexts to share localStorage or sessionStorage — a subdomain difference like api. versus app. creates entirely separate storage. Some browsers additionally partition storage by top-level site in third-party contexts to limit cross-site tracking, which can surprise embedded widgets that expect persistent state.
- Don't assume sibling subdomains can read each other's localStorage.
- Third-party iframe storage can be more restricted or short-lived than same-site storage.
- Cookies can be scoped more broadly across subdomains via the Domain attribute, unlike localStorage.
QAInterview questions and model answers
Attempt each answer aloud before opening it. The model answer shows the depth and precision expected in an interview; it is not a script to memorize.
Intermediate · Conceptual · 1 min · Question 1What is the practical size limit of localStorage?Open model answer
Model answer
It commonly caps around 5 to 10 MB per origin depending on the browser, and it stores strings only, so objects must be serialized. Exceeding the limit throws a QuotaExceededError.
Open question page →Intermediate · Conceptual · 1 min · Question 2How does sessionStorage differ from localStorage in scope?Open model answer
Model answer
sessionStorage is isolated per browsing-context tab or window and is cleared when that tab closes, while localStorage persists across restarts and is shared by every tab for the same origin.
Open question page →Intermediate · Conceptual · 1 min · Question 3Why is IndexedDB preferred for larger datasets?Open model answer
Model answer
It is asynchronous, so it doesn't block the main thread, supports structured and binary data, indexes, and transactions, and has a much larger practical storage quota than localStorage or sessionStorage.
Open question page →Intermediate · Conceptual · 1 min · Question 4What makes a cookie automatically sent with a request?Open model answer
Model answer
Its Domain and Path attributes match the request URL, it hasn't expired, and its Secure/SameSite attributes permit sending it in that request's context — the browser attaches matching cookies without any JavaScript involvement.
Open question page →Intermediate · Conceptual · 1 min · Question 5Why is storing an auth token in localStorage a common security concern?Open model answer
Model answer
Any script executing in that origin, including an injected XSS payload, can read localStorage directly. There is no equivalent to a cookie's HttpOnly flag for localStorage.
Open question page →Intermediate · Conceptual · 1 min · Question 6Can two different subdomains share localStorage?Open model answer
Model answer
No. localStorage is partitioned by full origin, meaning scheme, host, and port must match exactly; app.example.com and api.example.com have separate localStorage even though they share a parent domain.
Open question page →Beginner · Conceptual · 1 min · Question 7Does clearing browser cookies also clear localStorage?Open model answer
Model answer
Not necessarily — they are separate storage mechanisms with separate browser UI and APIs, though a full 'clear site data' action typically removes both.
Open question page →Advanced · Conceptual · 1 min · Question 8How can multiple tabs of the same origin communicate through storage?Open model answer
Model answer
A storage event fires in other same-origin tabs when localStorage changes, letting them react to updates such as a logout performed in one tab without any network call.
Open question page →Advanced · Conceptual · 1 min · Question 9What happens to sessionStorage data when a tab is duplicated?Open model answer
Model answer
The duplicated tab receives a copy of the original tab's sessionStorage at the moment of duplication, but the two tabs' storage then evolves independently.
Open question page →Advanced · Conceptual · 1 min · Question 10Why might Safari's storage behavior surprise developers testing cross-site scenarios?Open model answer
Model answer
Some browsers apply storage partitioning or limit persistence for storage set in a third-party or cross-site context to reduce tracking, so data can be evicted sooner than on same-site usage.
Open question page →SCScenario questions
Scenario 1
A single-page app needs to persist a multi-step form draft that should survive an accidental tab close but not follow the user to a different device.
- Decide the draft doesn't need to reach the server on every keystroke.
- Choose localStorage over sessionStorage so an accidental close doesn't lose it.
- Avoid IndexedDB unless the draft includes large attachments.
- Clear the stored draft once the form successfully submits.
Reveal worked answer
I would use localStorage keyed by a draft id, since the requirement is surviving tab close, which sessionStorage would not satisfy. I would avoid storing anything sensitive like payment details in it, and explicitly clear the entry after successful submission so stale drafts don't reappear.