22. Storage (localStorage / sessionStorage / cookies)
localStorage persists data per origin. It survives until you explicitly remove it.
What you'll learn
- 1Know the differences between the three browser storage options.
- 2Use the localStorage / sessionStorage APIs.
- 3Understand what cookies are and where they fit.
- 4Pick the right storage for the job.
Overview
localStorage persists data per origin. It survives until you explicitly remove it.
Core Concepts
1. localStorage
localStorage persists data per origin. It survives until you explicitly remove it.
localStorage.setItem('username', 'Hong Gildong');
const name = localStorage.getItem('username');
localStorage.removeItem('username');
localStorage.clear();Values are **always strings**. Serialize objects with `JSON.stringify` first.
2. sessionStorage
Cleared when the tab closes. Same API as localStorage.
sessionStorage.setItem('cart', JSON.stringify([1, 2, 3]));3. Cookies (overview)
- Small text values automatically exchanged with the server.
- Used for auth tokens, session IDs.
- About 4KB max β attached to every request, so be mindful of traffic.
- Browser access via `document.cookie` exists but is discouraged. Setting via the server's `Set-Cookie` header is standard.
4. Comparison
| Aspect | localStorage | sessionStorage | Cookies |
|---|---|---|---|
| Lifetime | Forever | Until tab closes | Configurable expiry |
| Capacity | ~5β10 MB | ~5β10 MB | ~4 KB |
| Sent to server | No | No | Automatic |
| Use case | Settings, cache | Temporary state | Authentication |
Examples
| File | What it covers |
|---|---|
| 01_localstorage.js | localStorage basics |
| 02_sessionstorage.js | sessionStorage basics |
| 03_cookie_overview.js | Reading cookies |
| 04_comparison.js | Comparing the three |
Run each file from the browser console or as a `<script>` in a blank HTML page.
src/01_localstorage.js
/**
* localStorage basics β run from a browser console
*/
localStorage.setItem('username', 'Hong Gildong');
console.log(localStorage.getItem('username'));
const user = { id: 1, name: 'Yi Sunshin' };
localStorage.setItem('user', JSON.stringify(user));
const restored = JSON.parse(localStorage.getItem('user'));
console.log(restored.name);
localStorage.removeItem('username');
// localStorage.clear(); // wipe everything
src/02_sessionstorage.js
/**
* sessionStorage β cleared when the tab closes
*/
sessionStorage.setItem('step', '1');
console.log(sessionStorage.getItem('step'));
sessionStorage.setItem('cart', JSON.stringify([
{ id: 1, qty: 2 },
{ id: 5, qty: 1 },
]));
const cart = JSON.parse(sessionStorage.getItem('cart'));
console.log('total qty:', cart.reduce((s, i) => s + i.qty, 0));
src/03_cookie_overview.js
/**
* Cookie overview β document.cookie returns all cookies as a single string
*/
console.log('current cookies:', document.cookie);
// Set (1 day expiry, all paths)
const oneDay = 60 * 60 * 24;
document.cookie = `lang=en; max-age=${oneDay}; path=/`;
// Parse example
const cookies = Object.fromEntries(
document.cookie.split('; ').filter(Boolean).map((c) => c.split('=')),
);
console.log(cookies);
src/04_comparison.js
/**
* Comparison demo of all three storage options
*/
localStorage.setItem('demo', 'L');
sessionStorage.setItem('demo', 'S');
document.cookie = 'demo=C; path=/';
console.log('local:', localStorage.getItem('demo')); // persistent
console.log('session:', sessionStorage.getItem('demo')); // tab-limited
console.log('cookie:', document.cookie); // sent to server
Common Mistakes
- Storing an object directly β you'll get the literal string `[object Object]`.
- Forgetting that `getItem` can return `null` and not handling it.
- Putting sensitive data (passwords, etc.) in localStorage.
- Assuming sessionStorage is shared across new tabs (it isn't).
- Hand-rolling cookies via `document.cookie` and ignoring security flags.
FAQ
Q1. Does data persist in incognito mode?
Everything is wiped when the window closes. **Q2. What if I exceed the quota?** A. You get a `QuotaExceededError`. **Q3. Do different domains share storage?** A. No β storage is isolated per origin.
Practice
Build a small notepad and a dark-mode toggle that both persist to localStorage.
homework/README.md
## Homework 1 β Notepad. Save the value of a `<textarea>` to localStorage so it survives reloads.
## Homework 2 β Dark-mode toggle. Toggle dark mode with a button and persist the choice to localStorage.
- Add a `dark` class to `<body>` when in dark mode.
homework/answer/homework_01.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Notepad</title>
</head>
<body>
<h1>My notes</h1>
<textarea id="memo" rows="10" cols="40"></textarea>
<script src="homework_01.js"></script>
</body>
</html>
homework/answer/homework_01.js
/**
* Homework 1: notepad backed by localStorage
*/
const KEY = 'memo:text';
const memo = document.getElementById('memo');
memo.value = localStorage.getItem(KEY) ?? '';
memo.addEventListener('input', () => {
localStorage.setItem(KEY, memo.value);
});
homework/answer/homework_02.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Dark mode</title>
<style>
body { background: #fff; color: #222; transition: 0.2s; }
body.dark { background: #222; color: #eee; }
</style>
</head>
<body>
<button id="toggle">Toggle dark mode</button>
<script src="homework_02.js"></script>
</body>
</html>
homework/answer/homework_02.js
/**
* Homework 2: dark-mode toggle + persistence
*/
const KEY = 'theme';
const btn = document.getElementById('toggle');
if (localStorage.getItem(KEY) === 'dark') {
document.body.classList.add('dark');
}
btn.addEventListener('click', () => {
document.body.classList.toggle('dark');
const mode = document.body.classList.contains('dark') ? 'dark' : 'light';
localStorage.setItem(KEY, mode);
});
Next Lecture
[23_Modules_ESM](../23_λͺ¨λ_ESM/)
All lecture materials and example code are openly available on GitHub.
View on GitHub β