Innovate | Connect | Transform
ContactService statusUSD $

GICT knowledge base

Cookies vs LocalStorage vs SessionStorage: What Each One Exactly Means

Published

web development
photo_6147878739858100400_y

Every website you visit stores something in your browser. Sometimes it is a session ID. Sometimes it is the dark mode preference you toggled on at 2am. Sometimes it is an unfinished form that vanished when your tab crashed. These are not accidents. They are three distinct storage mechanisms built into every browser, and they work in very different ways.

Understanding the difference matters more than it sounds. Storing an auth token in the wrong place opens your app to XSS attacks. Setting a limit on API requests without knowing which storage type your framework uses means your rate limiter breaks silently. I have seen both happen in production.

Here is what each one actually does.

Cookies: Data That Travels with Every Request

Cookies are the oldest browser storage mechanism, and they behave differently from the other two in one critical way: the browser sends them to the server automatically with every HTTP request.

When you log into a site and the server sets a session cookie, your browser stores it and attaches it to every subsequent request. Page loads, API calls, and image fetches all carry it. The server sees it on every single one. This is why cookies are the right choice for anything the server needs to know about you.

The basics

A cookie is a name-value pair with some attributes attached:

session_id=abc123; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=86400

The name and value are just strings. The attributes control everything else. Path determines which URLs on your site the cookie applies to. Secure means it only travels over HTTPS. HttpOnly means JavaScript cannot read it. This matters for security, which I will get to shortly.

Cookie size and lifetime

Cookies are tiny. The browser limit is 4KB per cookie, including all attributes. You can store a session ID or a short auth token, but not much else. If you try to put a long string into a cookie, the browser silently truncates it or rejects it depending on the browser engine. This is not always obvious in testing, so it bites you in production when a username that should be 50 characters gets cut to 20 and nobody notices until a user complains.

There are two lifetime types. A session cookie disappears when you close the browser. A persistent cookie has an expiration date or Max-Age, and it survives browser restarts. The distinction matters for “remember me” checkboxes versus shopping cart sessions. On a banking site you probably want the shorter session lifetime. On a news site you want persistent so your preferences survive a restart.

When cookies make sense

Use cookies when the server needs to read the data. Auth tokens, session IDs, CSRF tokens, and anything that drives server-side logic belongs here. The automatic request attachment means your server always has it without any client-side code having to remember to send it.

LocalStorage: Persistent Storage That Lives in Your Browser

LocalStorage is a JavaScript API for storing key-value data that persists after you close the browser. It was introduced as part of HTML5 and gave developers something cookies could not offer: more space and no automatic server transmission.

The API

The localStorage object lives on the window. The interface is deliberately simple:

// Store
localStorage.setItem('theme', 'dark');

// Retrieve
const theme = localStorage.getItem('theme');

// Remove
localStorage.removeItem('theme');

// Clear everything
localStorage.clear();

Values are always strings. Storing an object requires serializing it first:

const user = { name: 'Alice', plan: 'pro' };
localStorage.setItem('user', JSON.stringify(user));

const stored = JSON.parse(localStorage.getItem('user'));

Size and lifetime

LocalStorage gives you roughly 5-10MB depending on the browser. That is orders of magnitude more than cookies. The data survives browser restarts and even device reboots. It does not expire unless you explicitly remove it or the user clears their browser data.

Domain-scoped and isolated

Data stored on example.com is only accessible to JavaScript running on example.com. A script on tracker.example.com cannot read data stored by example.com. This is the same-origin rule: scheme + domain + port must all match.

When localStorage makes sense

Use it for data the client needs to remember without involving the server. Theme preferences, language settings, collapsed menu states, last-visited timestamps. These are all good fits. A news site might store your preferred sections. A productivity app might store your last opened workspace.

Do not store anything sensitive here. Because localStorage is accessible to any JavaScript running on your page, a cross-site scripting attack can read everything in it.

SessionStorage: Tab-Only Storage

SessionStorage works almost exactly like localStorage, with one crucial difference: the data survives page refreshes but disappears when you close the tab.

The API

The interface is identical to localStorage:

sessionStorage.setItem('draft', 'My unfinished blog post...');
const draft = sessionStorage.getItem('draft');
sessionStorage.removeItem('draft');

You can swap localStorage for sessionStorage in most code without changing anything else.

Tab isolation

SessionStorage is isolated per tab. Open the same site in two tabs and each tab has its own separate storage. Changing something in tab A does not affect tab B. This is useful for temporary state that should not leak between tabs.

When sessionStorage makes sense

Use it for anything that should not outlive the current session. Form drafts are the classic example. If your user is writing a long post and accidentally closes the tab, sessionStorage will lose it. For that reason, some apps use sessionStorage as a temporary buffer before saving to the server.

Shopping carts are another case. If you add an item in one tab and open a fresh tab to compare prices, the cart should be independent. SessionStorage handles this naturally.

—

Side by Side

Here is the quick comparison when you are choosing between the three:

                  Cookies         LocalStorage     SessionStorage
---------------------------------------------------------------------------
Size              4KB             5-10MB           5-10MB
Lifetime          Server/set      Persistent       Tab close
Server access     Automatic       JavaScript only  JavaScript only
Sent with reqs    Yes             No               No
HttpOnly option   Yes             No               No
Same-origin       Yes             Yes              Yes (per tab)

Notice the HttpOnly column. Cookies can be marked HttpOnly, which tells the browser to never expose them to JavaScript. This is the main security advantage cookies have over the other two. If you store your auth token in localStorage and someone injects a script into your page, they can read that token. HttpOnly cookies are invisible to JavaScript, so they survive XSS attacks that would otherwise steal session IDs.

Security Traps to Avoid

Never put sensitive data in localStorage

This cannot be said enough. Auth tokens, API keys, personal data. None of it belongs in localStorage or sessionStorage. Anything JavaScript can read, an XSS payload can steal. If you control the server and the data does not need to reach the client, keep it server-side. If you must store a token client-side, use an HttpOnly cookie.

SameSite prevents CSRF, not XSS

SameSite=Strict blocks cross-site requests from sending the cookie at all. SameSite=Lax allows it on GET requests like link clicks but blocks POST requests from other sites. This is effective against cross-site request forgery, but it does nothing against XSS. SameSite is a CSRF defense layer, not an XSS defense. You still need Content Security Policy headers and input sanitization to stop XSS attacks.

The subdomain problem

Data in localStorage is isolated by exact origin. If you have app.example.com and blog.example.com, they cannot read each other’s localStorage even though they share the root domain. This is by design. But if you allow user-generated content on a subdomain, that subdomain can run JavaScript and read its own localStorage. It can also read any auth tokens stored by your main app if they share the same parent domain through a misconfigured domain attribute on a cookie.

Which One Should You Use

Three questions get you to the right answer every time.

Does the server need this data? If yes, use a cookie. Does the data need to survive closing the browser? If yes and it is not sensitive, use localStorage. Does it only need to survive the current tab session? If yes, use sessionStorage.

In practice, modern web apps tend to use a combination. Auth tokens often live in HttpOnly cookies for security. Theme preferences and UI state live in localStorage. Form drafts and per-tab state live in sessionStorage. None of them compete. They complement each other.

Pick the one that fits the job. Forgetting which one does what is how you end up with auth tokens in localStorage and a surprise XSS vulnerability six months later.

Related guides

Account services are unavailable until the production backend is configured.