glimfly
code updated

Local storage, session storage, cookies: where your app remembers you

In one sentence:Cookies, localStorage, and sessionStorage are the three places a browser stores data for your app: cookies ride along to the server and can expire, localStorage stays until cleared, sessionStorage dies with the tab.

What it actually is

Your browser gives every site three separate pockets for storing data on your machine: cookies, localStorage, and sessionStorage. They look alike from the outside. They differ in two ways that matter: who gets to see them, and how long they live.

Think of a gym. A cookie is your membership wristband: the gym put it on you, the front desk checks it on every visit, and it expires when your membership does. localStorage is your rented locker: your stuff stays in it until someone clears it out, and the front desk never sees inside. sessionStorage is the day-use locker by the pool, emptied the moment you leave.

CookieslocalStoragesessionStorage
Sent to the serverAutomatically, with every request to that siteNeverNever
How long it livesUntil its expiry date, or until the session endsUntil the site or the user clears itUntil the tab closes
Readable by JavaScriptYes, unless flagged HttpOnlyAlwaysAlways

That first row is the one to remember. Cookies travel in the Cookie header on every request to that site, which is how the server recognizes you. The storage pockets never leave your machine unless your JavaScript sends them somewhere on purpose.

Why your AI just did this

localStorage is the cheapest persistence there is, so your agent reaches for it constantly. Ask for “remember dark mode” or “keep the cart when the page refreshes” and you’ll get a line like localStorage.setItem('theme', 'dark'), no database needed. It’s a fine home for low-stakes state like preferences or drafts. A classic surprise follows: before your project has a real database, agents often fake saving with localStorage, so “saved” data lives in one browser on one device.

Login is where the choice gets serious. Your agent picks one of two auth patterns, and it doesn’t always announce which. Either the server sets a session cookie (often flagged HttpOnly, so JavaScript can’t read it) and the browser returns it automatically, or the app saves a token, often a JWT, in localStorage and attaches it to each request by hand in an Authorization header.

The caution you’ll hear about the second pattern: everything in localStorage is readable by any JavaScript running on your page. If an attacker gets a script onto the page, through an XSS hole or a compromised dependency, it can read the token and use it. OWASP’s advice is to keep session identifiers in an HttpOnly cookie instead, which stays unreadable even then. Plenty of serious apps still ship tokens in localStorage and lean on other defenses; the point is to know which pattern yours uses, and to have picked it on purpose.

When you’ll run into it

Open DevTools (F12) and find the Application tab (Storage in Firefox). Cookies, Local storage, and Session storage each get their own section, per site. This is where “why am I still logged in” stops being a mystery. Signed in after a full browser restart? A cookie with a future expiry date, or a token in localStorage. Treated like a stranger in every new tab? The session sits in sessionStorage, which each tab keeps separately.

The famous “clearing site data fixed it” moment lives here too. Apps evolve; old saved data doesn’t. Your app once stored cart as a list, the new version expects an object, and the page breaks only for people who visited last week. Clear site data (a button in the Storage section of that same Application tab) wipes all three pockets, the app starts from nothing, and the bug vanishes. The durable fix is code that tolerates missing or outdated keys, the same instinct as input validation on a server.

Two more sightings. A server-rendered app can crash with localStorage is not defined, because that render ran in Node first, where browser storage doesn’t exist. And in private or incognito windows, localStorage behaves like sessionStorage: the browser deletes it when the private window closes, so incognito amnesia is by design.

What to check

  • Read what your app actually stores in each pocket of the Application tab; key names like token or session tell you where login lives
  • Ask your agent whether login uses an HttpOnly cookie or a token in localStorage, and to explain the tradeoff it picked
  • Inspect your session cookie’s flags in that same tab; HttpOnly and Secure should be checked for anything auth-related
  • Handle missing or outdated keys in code that reads storage, so last month’s data doesn’t crash the page
  • Keep server secrets out of all three pockets; anything in the browser sits on the user’s machine
  • Reproduce “works for me, broken for them” bugs in an incognito window first; if the bug vanishes there, stale storage is your suspect

Say it like a dev

Instead of: “the site logs me out every time I open a new tab” Say: “Are we keeping the session in sessionStorage? Move it to a cookie or localStorage if it should survive new tabs.”

Instead of: “clearing my cache fixed it, so is my app broken?” Say: “The bug only happens with old localStorage data. Add handling for missing or outdated keys instead of assuming they exist.”

Instead of: “put the login token wherever it works” Say: “Where does the auth token live, an HttpOnly cookie or localStorage? If it’s localStorage, walk me through the XSS tradeoff we’re accepting.”

People actually ask

“Why do I stay logged in even after closing my browser?”

Because the app stored something durable: either a cookie with an expiry date in the future or a token in localStorage, and both survive a full browser restart. When you come back, the cookie rides along with your requests automatically, or the app's JavaScript reads the saved token and presents it. You stay logged out only when that stored piece expires or gets cleared.

“Why does clearing site data fix weird bugs?”

Clearing site data wipes cookies, localStorage, and sessionStorage for that site, so the app restarts from a blank slate. Weird states often come from old saved data that a newer version of the app no longer understands, like a value stored in a shape the current code doesn't expect. Wiping it hides the symptom; the durable fix is code that handles missing or outdated stored data.

“Is it safe to keep my login token in localStorage?”

It works, and many apps do it, but anything in localStorage can be read by any JavaScript running on the page, so a cross-site scripting (XSS) hole would expose the token. OWASP recommends keeping session identifiers in cookies flagged HttpOnly instead, because JavaScript can't read those at all. Ask your agent which pattern your app uses and why, so the choice is deliberate rather than accidental.

Related terms

Checked against

free tool · no signup

Just met this in a real session? Glim reads it in plain words.

Paste what your agent just did, a git diff, your terminal, or its summary, and Glim tells you what changed and what to check before you ship. Nothing stored.

Explain my session →