JavaScript localStorage

Remember data between visits with localStorage and sessionStorage.

Lesson 41 of 56Intermediate13 min read

Refresh the page and every variable is gone. localStorage lets you save small amounts of data in the browser so it's still there next time: a visitor's chosen theme, a draft message, a to-do list or a game's high score. No server or database is needed.

localStorage is one of the simplest ways to make a small app feel complete. A to-do list that forgets everything on refresh feels like a demo; one that remembers its items feels like a real tool. This lesson shows how to save and load data safely, including arrays and objects.

The four localStorage methods

JavaScript
localStorage.setItem("theme", "dark");     // save
localStorage.getItem("theme");             // "dark" (or null if missing)
localStorage.removeItem("theme");          // delete one item
localStorage.clear();                      // delete everything for this site

Data is stored as pairs of string keys and string values. Each website gets its own separate storage, and the data has no expiry date. It stays until your code or the visitor removes it.

Storing arrays and objects with JSON

localStorage only stores strings. Convert arrays and objects with JSON:

JavaScript
localStorage.setItem("todos", JSON.stringify(todos));
const todos = JSON.parse(localStorage.getItem("todos")) ?? [];

The ?? [] provides a sensible default the first time the page loads, when nothing has been saved yet.

If you store a number, it comes back as a string, so "5" needs converting with Number() before you do maths with it.

sessionStorage

sessionStorage has exactly the same methods, but its data disappears when the tab is closed. It's useful for temporary information, such as the progress of a half-finished form in one tab.

Limits and safety

  • Each site gets roughly 5MB of storage.
  • Visitors can see and edit the data in DevTools (in the Application tab), so never store passwords or other secrets there.
  • Storage can be unavailable, for example in some private browsing modes, so wrap it in try...catch in real apps.
  • Saving and loading is synchronous, so keep the amount of data small to avoid slowing the page down.

localStorage vs other storage options

OptionLastsSizeGood for
localStorageUntil clearedAbout 5 MBPreferences, drafts, small saved lists
sessionStorageUntil the tab closesAbout 5 MBA multi-step form in one tab
CookiesSet expiry dateAbout 4 KBData the server must read on every request
IndexedDBUntil clearedHundreds of MBLarge data, offline apps, files

All of them belong to one site only: a page on another domain can't read your localStorage. But any script running on your page can, including third-party scripts, so never store passwords, payment details or private tokens there. The storage event fires in your other open tabs when a value changes, which lets several tabs stay in sync.

localStorage Syntax

localStorage

localStorage.setItem("key", "value");
const value = localStorage.getItem("key");
localStorage.setItem("list", JSON.stringify([1, 2]));
const list = JSON.parse(localStorage.getItem("list")) ?? [];

localStorage Summary

  • localStorage saves string data in the browser between visits.
  • Use setItem, getItem, removeItem and clear to manage it.
  • Convert arrays and objects with JSON.stringify and JSON.parse.
  • sessionStorage works the same way but clears when the tab closes.
  • Never store secrets in localStorage, and handle the case where it's unavailable.

localStorage Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

Saving a preference

Pick a colour, then press Run again. Your choice is remembered. (Previews on this site use a safe in-memory stand-in for storage.)

const picker = document.querySelector("#fav");
const msg = document.querySelector("#msg");

const saved = localStorage.getItem("favColor") ?? "#17a865";
picker.value = saved;
msg.textContent = `Saved colour: ${saved}`;

picker.addEventListener("input", () => {
  localStorage.setItem("favColor", picker.value);
  msg.textContent = `Saved colour: ${picker.value}`;
});
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 4Load the saved value, or a default the first time.
  2. Lines 8 to 11Save whenever the user picks a new colour.
Example 2

Storing an array with JSON

const key = "visits";

const visits = JSON.parse(localStorage.getItem(key)) ?? [];
visits.push(new Date().toLocaleTimeString());
localStorage.setItem(key, JSON.stringify(visits));

console.log(`You've run this ${visits.length} time(s):`);
console.log(visits);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 3Read the saved array (or start empty).
  2. Line 4Add the current time.
  3. Line 5Save the whole array back as a JSON string.
Example 3

A to-do list that survives refresh

const form = document.querySelector("#add");
const input = document.querySelector("#task");
const list = document.querySelector("#list");

let tasks = JSON.parse(localStorage.getItem("tasks")) ?? [];

function render() {
  list.replaceChildren();
  for (const t of tasks) {
    const li = document.createElement("li");
    li.textContent = t;
    list.append(li);
  }
}

function save() {
  localStorage.setItem("tasks", JSON.stringify(tasks));
}

form.addEventListener("submit", (e) => {
  e.preventDefault();
  tasks.push(input.value.trim());
  input.value = "";
  save();
  render();
});

document.querySelector("#clear").addEventListener("click", () => {
  tasks = [];
  save();
  render();
});

render();
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 5Load saved tasks once at the start.
  2. Lines 7 to 14One function draws the list from the data.
  3. Lines 16 to 18One function saves the data.
  4. Lines 20 to 26On submit: update data → save → re-render.

Common localStorage Mistakes

Storing objects without JSON

Don't
localStorage.setItem("user", { name: "Ali" });
localStorage.getItem("user"); // "[object Object]"
Do
localStorage.setItem("user", JSON.stringify({ name: "Ali" }));
JSON.parse(localStorage.getItem("user")); // { name: "Ali" }

Forgetting numbers come back as strings

Don't
const score = localStorage.getItem("score"); // "10"
score + 5; // "105"
Do
const score = Number(localStorage.getItem("score") ?? 0);
score + 5; // 15

localStorage in Real Projects

Where localStorage is used

Theme and language preferences, "remember my cart" on shops, draft emails, onboarding tips you've dismissed, offline note apps and browser games' save slots. For large or private data, apps use IndexedDB or a server instead.

localStorage Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Save and then read the user's name.

localStorage.("username", "Ola");
const name = localStorage.("username");
Multiple choiceeasy

What does localStorage.getItem("missing") return?

Multiple choicemedium

How do you store an array in localStorage?

Fix the bugmedium

The high score should be saved as a number and doubled to log Double: 84. Fix the reading code.

localStorage.setItem("high", JSON.stringify(42));

const high = localStorage.getItem("high");
console.log("Double:", high + high);
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • Logs "Double: 84"

localStorage Quiz

3 questions to check what you learned.

  1. Does localStorage data survive a page refresh?

    • No
    • Only for 1 hour
    • Yes
    • Only in Chrome
  2. What's the difference between localStorage and sessionStorage?

    • sessionStorage is cleared when the tab closes
    • sessionStorage is bigger
    • localStorage is server-side
    • No difference
  3. Should you store passwords in localStorage?

    • No. It's readable by any script on the page and in DevTools
    • Yes, it's encrypted
    • Only short ones
    • Only in sessionStorage

localStorage Challenge

Remember the click count

Make a counter that survives refresh:

  1. Read clicks from localStorage (default 0) and show it in #n
  2. On each click of #btn, add 1, save it, and update #n
const btn = document.querySelector("#btn");
const n = document.querySelector("#n");
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Clicking updates the display
  • The count is saved