Browser Storage
Different ways a website can save small pieces of data directly in the user's browser, so it's still there the next time they visit.
What is it?
Normally, everything a page knows about disappears the moment you close the tab or navigate away — variables in JavaScript, form input that hasn't been submitted, anything held only in memory. Sometimes a site needs to remember something across visits or page loads: that you're logged in, that you prefer dark mode, that you had three items in a cart.
Browsers give websites a few different tools for this, and picking between them comes down to how long the data should last and who needs to see it. Cookies are small pieces of data that get automatically sent along with every request to a server, which makes them the classic way a server keeps track of a logged-in session. localStorage saves data only in the browser, with no automatic connection to the server, and it sticks around indefinitely until something explicitly clears it. sessionStorage works just like localStorage, but it's wiped out as soon as that specific browser tab is closed.
None of these are a full database — they're all meant for relatively small amounts of data, stored on the one device and browser someone happens to be using.
Explain like I'm 10
A cookie is like a stamped hand at a venue — you show it every time you walk up to a counter (the server) so they recognize you. localStorage is like a locker you keep at home that stays packed until you empty it yourself. sessionStorage is like a locker at the venue itself — once you leave for the night, it's cleared out.
Examples
localStorage vs. sessionStorage
// Persists even after closing and reopening the browser
localStorage.setItem("theme", "dark");
// Cleared automatically once this tab is closed
sessionStorage.setItem("draftText", "Hello, world");
// Reading values back later
const theme = localStorage.getItem("theme");Both use the same simple key-value API, but localStorage data survives closing the browser entirely, while sessionStorage data disappears once that tab is closed.
A basic cookie
document.cookie = "sessionId=abc123; max-age=3600";Unlike localStorage or sessionStorage, this cookie is automatically attached to every future request this browser makes to the same site, which is what lets a server recognize a returning user without any extra JavaScript on the server's end.
How it works
Cookies are stored by the browser and automatically included in the headers of every request sent to the domain that set them, which is exactly what lets a server recognize the same visitor across multiple requests. localStorage and sessionStorage, by contrast, are pure browser-side storage — nothing about them is sent to a server automatically; JavaScript has to explicitly read them and send their contents if a server needs to know about them. All three are scoped per origin, meaning one website generally can't read another website's stored data.
Why does it exist?
These tools exist because different problems need different lifetimes and different visibility. A login session needs the server to recognize you on every request, which is exactly what cookies were built for. A saved preference or draft only needs to live in the browser and doesn't need to burden every single network request with extra data, which is what localStorage and sessionStorage are for instead.
When to use it
Use cookies when the server itself needs to know the stored value on every request, like an authentication session. Use localStorage for settings or data that should persist across visits but only matter to the browser, like a saved theme preference. Use sessionStorage for short-lived, per-tab data that shouldn't outlive the current visit, like an in-progress multi-step form.
When not to use it
None of these are appropriate for large amounts of data or anything sensitive that truly needs strong protection — they're all readable from the browser's storage/dev tools by anyone with access to that device. For sensitive data or data that must be reliably shared across devices, that belongs on the server, in an actual database.
Common mistakes
Storing sensitive information like passwords directly in localStorage, where it's easily readable by anyone with device or script access.
Expecting sessionStorage data to persist after closing the tab, when it's specifically designed not to.
Overloading cookies with large amounts of data, which slows down every single request since cookies are sent with each one automatically.
Practice exercises
- Easy:
Use localStorage to save a user's chosen theme, and load it back when the page reopens.
- Medium:
Build a simple multi-step form that saves progress in sessionStorage, and confirm the progress disappears after closing the tab.
- Hard:
Explain, with a concrete scenario, why an authentication session is typically implemented using cookies rather than localStorage.
Interview questions
What's the key difference between cookies and localStorage?
Cookies are automatically sent with every request to the server that set them, making them suited for server-side session tracking. localStorage stays entirely in the browser and is never sent automatically.
What's the difference between localStorage and sessionStorage?
They share the same API, but localStorage persists indefinitely until explicitly cleared, while sessionStorage is cleared automatically once its specific tab is closed.
Why shouldn't sensitive data be stored in localStorage?
localStorage is plain, unencrypted browser storage readable by any script running on that page or anyone with access to the browser's dev tools, so it offers no real protection for sensitive values.
What are the typical size limits for localStorage/sessionStorage versus a single cookie?
localStorage and sessionStorage typically allow around 5-10MB per origin (varies by browser), while a single cookie is limited to roughly 4KB, and browsers also cap the total number of cookies allowed per domain.
Is the localStorage/sessionStorage API synchronous or asynchronous, and why does that matter?
It's synchronous — every read and write blocks the calling JavaScript thread until it completes. For small amounts of data this is unnoticeable, but storing or retrieving large values can briefly block the main thread and make the page feel unresponsive, which is one reason it's meant for small data only.
When would you reach for IndexedDB instead of localStorage?
When you need to store significantly more data, structured/queryable data (not just string key-value pairs), or want asynchronous access that doesn't block the main thread — IndexedDB supports indexes, transactions, and much larger storage quotas, at the cost of a considerably more complex API.
If a site is open in two different browser tabs, do they share the same localStorage data? What about sessionStorage?
localStorage is shared across every tab and window for the same origin — a write in one tab is immediately visible to the others. sessionStorage is scoped to that one specific tab/window, so each tab has its own independent sessionStorage even for the same site.
Does duplicating an existing browser tab preserve its sessionStorage, and does opening a fresh tab to the same URL do the same?
Duplicating a tab actually copies its sessionStorage into the new tab, since browsers treat it as continuing the same browsing context. Opening a brand-new tab and navigating to the same URL does not — that tab starts with empty sessionStorage, since it's a new top-level browsing context.
If a user clears their browser's cookies, does that also clear localStorage?
Not necessarily — cookies and localStorage are separate storage mechanisms, and a browser's 'clear cookies' option may or may not also clear other site data depending on the exact setting chosen ('cookies only' versus 'all site data'), so code shouldn't assume clearing one implies the other was cleared too.
What does the `HttpOnly` flag on a cookie do, and why does it matter for security?
It prevents the cookie from being read or written via document.cookie in JavaScript — only the browser's HTTP layer can access it. This blocks a common XSS attack path where injected script tries to steal a session cookie, since the malicious script simply can't see it.
What do the `Secure` and `SameSite` cookie attributes protect against?
Secure ensures the cookie is only ever sent over HTTPS connections, protecting it from being exposed on an unencrypted network. SameSite restricts whether the cookie is sent along with cross-site requests, which helps mitigate CSRF attacks that rely on a browser automatically attaching cookies to requests triggered from another site.
Why is an auth token often stored in a cookie rather than localStorage, from a security standpoint?
A cookie can be marked HttpOnly, making it invisible to JavaScript and therefore immune to being stolen via an XSS attack that injects malicious script. Anything in localStorage is always readable by any script running on the page, so an XSS vulnerability anywhere on the site can exfiltrate a token stored there directly.
What does 'same-origin' mean in the context of storage scoping?
Two URLs are same-origin only if their protocol, host, and port all match exactly. Storage (cookies have slightly different, host-based rules, but localStorage/sessionStorage strictly) is scoped per origin, so a script on one origin generally cannot read another origin's stored data.
How can one open tab find out that another tab just changed a value in localStorage?
By listening for the storage event on window — the browser fires it in every other same-origin tab/window when localStorage changes, passing along the key, old value, and new value.
Why doesn't the `storage` event fire in the same tab that made the change?
It's designed specifically to let other browsing contexts react to a change they didn't make themselves — the tab that performed the write already knows the new value directly, so firing the event there too would be redundant; the spec only dispatches it to other tabs/windows sharing that storage.
What does `localStorage.getItem("missingKey")` return if that key was never set?
It returns null, not undefined — so checking for a missing key should compare against null (or use a falsy check), not assume JavaScript's usual undefined for absent properties.
Why can localStorage only store strings, and how do you work around that to store objects?
The Web Storage API's get/setItem methods only accept and return strings by design. To store structured data, you serialize it with JSON.stringify() before saving and parse it back with JSON.parse() after reading, converting to/from a string representation each time.
What happens if you try to write more data than localStorage's quota allows?
The browser throws a QuotaExceededError (or similar DOMException) from setItem, rather than silently failing or truncating the data — so code writing potentially large values should wrap the call in a try/catch to handle that case gracefully.
What do a cookie's `path` and `domain` attributes control?
path restricts the cookie to being sent only for requests whose URL path starts with that value (e.g. limiting it to /admin). domain controls which hosts the cookie is sent to — set broadly enough, it can be shared across subdomains of the same site rather than being scoped to just the exact host that set it.
Why might a 'remember me' login feature use a long-lived cookie rather than a long-lived value in localStorage?
The server needs to recognize the returning user automatically on the very first request of a new visit, before any of the page's JavaScript has even run — a cookie is attached to that initial request by the browser itself, while localStorage is only accessible after the page's script executes and would require an extra round-trip to inform the server.