Skip to content
Laviyx Learn

Try

JavaScript course menu

localStorage and sessionStorage in JavaScript: Saving Data in the Browser

Learn the Web Storage API: saving, reading and removing data with localStorage and sessionStorage, storing objects with JSON, the differences between localStorage, sessionStorage and cookies, storage limits, the storage event, and what not to store.

Intermediate8 min readUpdated
On this page

Normally everything in a web page is lost when it is reloaded. The Web Storage API gives each website a small key-value store in the browser that survives reloads: perfect for theme choices, drafts, a shopping cart before checkout, or a to-do list.

Saving and reading#

JavaScript
localStorage.setItem("theme", "dark");

const theme = localStorage.getItem("theme");
console.log(theme);                          // "dark"

console.log(localStorage.getItem("missing")); // null

localStorage.removeItem("theme");
localStorage.clear();                        // remove everything for this site
MethodDoes
setItem(key, value)Saves a value under a key
getItem(key)Reads it, or null if it does not exist
removeItem(key)Deletes one key
clear()Deletes all keys for this site
length, key(i)Count the keys and read a key by position

Only strings#

Web Storage stores strings only. Numbers become strings, and objects become the useless string "[object Object]":

JavaScript
localStorage.setItem("count", 5);
console.log(typeof localStorage.getItem("count"));  // "string"

localStorage.setItem("user", { name: "Asha" });
console.log(localStorage.getItem("user"));          // "[object Object]"

Use JSON to store objects and arrays:

JavaScript
const cart = [{ id: 1, qty: 2 }, { id: 7, qty: 1 }];
localStorage.setItem("cart", JSON.stringify(cart));

const saved = JSON.parse(localStorage.getItem("cart") ?? "[]");
console.log(saved.length);   // 2

?? "[]" provides a default when nothing has been saved yet.

A safe helper#

Stored data can be missing, corrupted, or blocked (some browsers block storage in private modes or when the user disables site data). Wrap access in try...catch:

JavaScript
function load(key, fallback) {
  try {
    const raw = localStorage.getItem(key);
    return raw === null ? fallback : JSON.parse(raw);
  } catch {
    return fallback;
  }
}

function save(key, value) {
  try {
    localStorage.setItem(key, JSON.stringify(value));
  } catch {
    // storage is full or unavailable: the app keeps working without saving
  }
}

A to-do list that survives reloads#

Save this as an HTML file and open it in your browser. Add some items, reload the page, and they are still there:

todo.html (HTML)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>Saved to-do list</title></head>
<body>
  <form id="form"><input id="task" placeholder="New task" required> <button>Add</button></form>
  <ul id="list"></ul>
  <script>
    const list = document.querySelector("#list");
    const input = document.querySelector("#task");
    let tasks = JSON.parse(localStorage.getItem("tasks") ?? "[]");

    function render() {
      list.replaceChildren(...tasks.map((text) => {
        const li = document.createElement("li");
        li.textContent = text;
        return li;
      }));
    }

    document.querySelector("#form").addEventListener("submit", (event) => {
      event.preventDefault();
      tasks.push(input.value.trim());
      localStorage.setItem("tasks", JSON.stringify(tasks));
      input.value = "";
      render();
    });

    render();
  </script>
</body>
</html>

The pattern is: load the saved data on start, render it, and save again after every change.

localStorage, sessionStorage or cookies?#

localStoragesessionStorageCookies
LastsUntil deletedUntil the tab is closedUntil an expiry date
Shared between tabsYes, same siteNo, one tab onlyYes
Sent to the server automaticallyNoNoYes, with every request
SizeTypically about 5 MB per siteTypically about 5 MB per siteAbout 4 KB each
Readable by JavaScriptYesYesYes, unless HttpOnly

sessionStorage has exactly the same methods as localStorage; only its lifetime differs. Use it for temporary state such as a multi-step form in one tab.

Storage is separate for each origin (scheme, domain and port), so one website cannot read another's data.

Listening for changes from other tabs#

When one tab changes localStorage, other open tabs of the same site receive a storage event, which you can use to keep them in sync:

JavaScript
window.addEventListener("storage", (event) => {
  if (event.key === "theme") applyTheme(event.newValue);
});

What not to store#

  • Secrets and sensitive data: passwords, card numbers, personal information. Any script running on the page, including a malicious one injected through an XSS bug, can read localStorage.
  • Authentication tokens: many teams prefer HttpOnly cookies, which JavaScript cannot read.
  • Large data: storage is small and synchronous (it blocks the page while reading and writing). For large or structured data, browsers provide IndexedDB.

Practice#

Practice exercise

Write two functions, saveSettings(settings) and loadSettings(), that store an object like { theme: "dark", fontSize: 18 } under the key "settings", and that return { theme: "light", fontSize: 16 } when nothing is saved or the saved data is broken.

Show solution
JavaScript
const DEFAULT_SETTINGS = { theme: "light", fontSize: 16 };

function saveSettings(settings) {
  try {
    localStorage.setItem("settings", JSON.stringify(settings));
  } catch {
    // ignore: settings just will not be remembered
  }
}

function loadSettings() {
  try {
    const raw = localStorage.getItem("settings");
    return raw ? { ...DEFAULT_SETTINGS, ...JSON.parse(raw) } : { ...DEFAULT_SETTINGS };
  } catch {
    return { ...DEFAULT_SETTINGS };
  }
}

Spreading the defaults first means a saved object missing a newer setting still gets its default value.

Key takeaway#

Finished this lesson?