JS localStorage API Guide: A Complete Tutorial
Learn how to store, retrieve, update, and remove data in the browser using the localStorage API with clear examples and practical patterns.
localStorage is a built-in browser API that stores key-value pairs directly in the user's browser. The data stays even after closing the tab, restarting the browser, or rebooting the computer.
It is the simplest way to save user preferences, form progress, or any small piece of state without a backend server.
Here is the smallest useful localStorage program you can write:
localStorage.setItem("username", "Rune");
console.log(localStorage.getItem("username"));The first line saves the string "Rune" under the key "username". The second line reads it back. If you close the browser tab, open a new one, and run only the getItem line, it still prints "Rune".
What localStorage actually stores
localStorage belongs to the browser's Web Storage API. It is a simple key-value dictionary attached to your site's origin. Every key and every value is a string. There is no schema, no data types, and no expiration.
| Property | Behavior |
|---|---|
| Scope | One origin (protocol + domain + port) |
| Capacity | About 5 MB per origin |
| Data type | Strings only |
| Lifetime | Permanent, until explicitly deleted |
| Shared | Yes, across all tabs of the same origin |
| Access | Synchronous (blocks the main thread for large operations) |
Because localStorage is synchronous, reading a single key is instant, but writing huge JSON blobs in a loop can briefly freeze the page. Keep stored values small.
The core methods
localStorage gives you five methods, but four cover virtually every real-world use case:
| Method | What it does |
|---|---|
| setItem(key, value) | Save a string value under a key |
| getItem(key) | Read a stored value, returns null if missing |
| removeItem(key) | Delete one key and its value |
| clear() | Delete every key for your origin |
Saving and reading data
The setItem method takes a key name and a string value. If the key already exists, the old value is overwritten.
localStorage.setItem("theme", "dark");
localStorage.setItem("fontSize", "16");
localStorage.setItem("notifications", "true");
const theme = localStorage.getItem("theme");
const missing = localStorage.getItem("doesNotExist");
console.log(theme);
console.log(missing);Running this code prints two values. The first getItem retrieves the saved theme. The second asks for a key that was never set, so it returns null.
dark
nullThe getItem call for "doesNotExist" returns null because that key was never set. Since getItem returns null for missing keys, never call string methods on its result without checking first.
Removing data
removeItem deletes a single key. The clear method wipes everything for your origin.
localStorage.removeItem("fontSize");
console.log(localStorage.getItem("fontSize"));
localStorage.clear();
console.log(localStorage.getItem("theme"));First removeItem deletes the fontSize key, then clear wipes every remaining key for this origin. Both getItem calls now return null since nothing is left:
null
nullBe careful with clear(). It removes every key your site has ever stored, including ones set by third-party scripts or libraries on the same origin.
Reading and writing non-string values
Since localStorage only accepts strings, you must convert numbers, booleans, and objects manually.
Numbers and booleans
localStorage.setItem("visits", String(42));
const visits = Number(localStorage.getItem("visits"));
console.log(visits + 1);
localStorage.setItem("subscribed", "true");
const subscribed = localStorage.getItem("subscribed") === "true";
console.log(subscribed);The code converts a stored number back to a real number for math, and compares a stored string to "true" for a real boolean. Here is the output:
43
trueCall Number() on the value you get back from storage. For booleans, compare against the string "true". Any other string becomes false.
Objects and arrays
localStorage cannot store objects directly. Serialize them with JSON.stringify before saving and deserialize with JSON.parse when reading. The companion article Storing Complex Objects in JS localStorage Guide covers this pattern in depth.
const user = { name: "Rune", level: 5 };
localStorage.setItem("user", JSON.stringify(user));
const saved = JSON.parse(localStorage.getItem("user"));
console.log(saved.name);After saving the object as JSON and reading it back, the name property is accessible again. Here is the result:
RuneAlways wrap JSON.parse in a try/catch block in real applications. If the stored value is corrupted or was written by buggy code, parsing will throw an error and break your script.
Reacting to changes across tabs
When you write to localStorage in one tab, other open tabs from the same origin receive a storage event. This keeps multiple tabs in sync without polling.
window.addEventListener("storage", (event) => {
console.log(`Key changed: ${event.key}`);
console.log(`Old value: ${event.oldValue}`);
console.log(`New value: ${event.newValue}`);
});The storage event only fires in tabs that did not trigger the change. If Tab A calls setItem, the event fires in Tab B, not Tab A.
Checking if localStorage is available
Some browsers block localStorage in private or incognito mode. Calling setItem can throw an error. Test availability once before relying on it:
function storageAvailable() {
try {
const testKey = "__storage_test__";
localStorage.setItem(testKey, testKey);
localStorage.removeItem(testKey);
return true;
} catch {
return false;
}
}If storageAvailable returns false, your code should fall back to in-memory storage or show a message to the user.
When to use localStorage
localStorage is the right choice when data needs to survive longer than a single page visit. Common use cases include user preferences like theme and font size, saving form drafts so work is not lost on refresh, caching API responses to avoid redundant network requests, tracking whether a user has seen a tutorial or dismissed a banner, and keeping a guest shopping cart for unauthenticated users.
For data that should disappear when the tab closes, use sessionStorage instead. For data the server needs to read automatically, use cookies instead of localStorage.
Common mistakes
- Storing objects without JSON.stringify saves the string "[object Object]" instead of your data.
- Not checking for null after getItem. Calling methods on null throws a TypeError.
- Using clear() carelessly removes data from every script on your origin, not just your own code.
- Storing too much data hits the 5 MB per-origin limit. Wrap setItem in try/catch.
- Assuming localStorage is always available. Private browsing mode can block it.
Related articles
- JS sessionStorage API Guide: Complete Tutorial -- temporary storage that clears when the tab closes
- How to Manage Cookies in JS: Complete Tutorial -- working with browser cookies
Quick reference
| Operation | Code |
|---|---|
| Save a value | localStorage.setItem("key", "value") |
| Read a value | localStorage.getItem("key") |
| Delete one key | localStorage.removeItem("key") |
| Delete all keys | localStorage.clear() |
| Check availability | Wrap setItem in try/catch |
| Listen for changes | window.addEventListener("storage", handler) |
Rune AI
Key Insights
- localStorage stores key-value pairs as strings that persist until explicitly removed.
- Use setItem, getItem, removeItem, and clear for all operations.
- Always handle the string-only limitation by converting numbers, booleans, and objects explicitly.
- Wrap JSON.parse calls in try/catch to avoid crashes on corrupted data.
- Listen for the storage event to keep multiple tabs in sync.
Frequently Asked Questions
How much data can I store in localStorage?
Does localStorage work across tabs?
Does localStorage expire?
Can I store objects directly in localStorage?
Conclusion
localStorage is the simplest way to keep data across page reloads and browser sessions without a server. Use setItem and getItem for basic reads and writes, remember that values are always strings, and handle the storage event if your app opens multiple tabs. For temporary data or objects, combine localStorage with JSON serialization or use sessionStorage.
More in this topic
Using Decorators for Logging in JS Architecture
Learn how JavaScript decorators wrap class methods to add logging without touching the original code, including setup with Babel and how execution order works.
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.