Academic Block

LocalStorage & SessionStorage Get Certified

The Web Storage API gives you two simple key-value stores that live in the browser: localStorage and sessionStorage. Both use the same methods, but they differ in how long the data lasts and whether it is shared across tabs.

Basic Usage: setItem, getItem, removeItem

The core methods are the same for both storage objects. Because this tutorial runs in a sandbox, the examples below use a small mock that behaves like the real Web Storage API.

What this code does: Demonstrates the three fundamental methods — storing a value, reading it back, and removing it.

function createMockStorage() {
    const data = {};
    return {
        setItem(key, value) {
            data[key] = String(value);
        },
        getItem(key) {
            return Object.prototype.hasOwnProperty.call(data, key) ? data[key] : null;
        },
        removeItem(key) {
            delete data[key];
        }
    };
}

const mockLocalStorage = createMockStorage();

mockLocalStorage.setItem("username", "Michael");
console.log(mockLocalStorage.getItem("username"));

mockLocalStorage.removeItem("username");
console.log(mockLocalStorage.getItem("username"));

getItem Returns null for Missing Keys

If a key has never been set (or has been removed), getItem() returns null instead of throwing an error.

What this code does: Shows that reading a key that does not exist safely returns null.

function createMockStorage() {
    const data = {};
    return {
        setItem(key, value) {
            data[key] = String(value);
        },
        getItem(key) {
            return Object.prototype.hasOwnProperty.call(data, key) ? data[key] : null;
        }
    };
}

const mockLocalStorage = createMockStorage();

console.log(mockLocalStorage.getItem("nonexistent"));
console.log(mockLocalStorage.getItem("nonexistent") === null);

clear() and the length Property

clear() removes every key at once. The length property tells you how many keys are currently stored.

What this code does: Stores a few items, checks the length, then clears everything and checks the length again.

function createMockStorage() {
    const data = {};
    return {
        setItem(key, value) {
            data[key] = String(value);
        },
        getItem(key) {
            return Object.prototype.hasOwnProperty.call(data, key) ? data[key] : null;
        },
        clear() {
            Object.keys(data).forEach(key => delete data[key]);
        },
        get length() {
            return Object.keys(data).length;
        }
    };
}

const mockLocalStorage = createMockStorage();

mockLocalStorage.setItem("username", "Michael");
mockLocalStorage.setItem("theme", "dark");
console.log("Before clear:", mockLocalStorage.length);

mockLocalStorage.clear();
console.log("After clear:", mockLocalStorage.length);

Storing Objects with JSON

Web Storage can only hold strings. To store an object or array, convert it with JSON.stringify() first, and convert it back with JSON.parse() when reading it.

What this code does: Stores a complex object by converting it with JSON.stringify and reading it back with JSON.parse.

function createMockStorage() {
    const data = {};
    return {
        setItem(key, value) {
            data[key] = String(value);
        },
        getItem(key) {
            return Object.prototype.hasOwnProperty.call(data, key) ? data[key] : null;
        }
    };
}

const mockLocalStorage = createMockStorage();

const user = { name: "Michael", age: 28 };
mockLocalStorage.setItem("user", JSON.stringify(user));

const storedUser = JSON.parse(mockLocalStorage.getItem("user"));
console.log(storedUser.name);
console.log(storedUser.age);

Everything Is Stored as a String

Even numbers and booleans are converted to strings when stored. You must convert them back to the correct type yourself when reading them.

What this code does: Highlights that Web Storage only holds strings — numbers and booleans are coerced when saved.

function createMockStorage() {
    const data = {};
    return {
        setItem(key, value) {
            data[key] = String(value);
        },
        getItem(key) {
            return Object.prototype.hasOwnProperty.call(data, key) ? data[key] : null;
        }
    };
}

const mockLocalStorage = createMockStorage();

mockLocalStorage.setItem("count", 5);
const value = mockLocalStorage.getItem("count");

console.log(typeof value);          // "string"
console.log(value + 1);             // "51" (concatenation)
console.log(Number(value) + 1);     // 6

Notice that value + 1 produces "51" (string concatenation), while Number(value) + 1 correctly produces 6.

Iterating Over All Stored Keys

The length property and key(index) method let you loop through every stored key without knowing their names in advance.

What this code does: Iterates over every stored key using the length property and key(index) method.

function createMockStorage() {
    const data = {};
    return {
        setItem(key, value) {
            data[key] = String(value);
        },
        getItem(key) {
            return Object.prototype.hasOwnProperty.call(data, key) ? data[key] : null;
        },
        key(index) {
            return Object.keys(data)[index] || null;
        },
        get length() {
            return Object.keys(data).length;
        }
    };
}

const mockLocalStorage = createMockStorage();

mockLocalStorage.setItem("username", "Michael");
mockLocalStorage.setItem("theme", "dark");
mockLocalStorage.setItem("language", "en");

for (let i = 0; i < mockLocalStorage.length; i++) {
    const key = mockLocalStorage.key(i);
    console.log(key + " = " + mockLocalStorage.getItem(key));
}

localStorage vs. sessionStorage

Both objects share the exact same interface — the difference is how long the data lasts. sessionStorage is scoped to a single tab and is cleared when that tab is closed; localStorage persists until it is explicitly removed, even after the browser is closed and reopened.

What this code does: Contrasts localStorage (persists across sessions) with sessionStorage (cleared when the tab closes).

function createMockStorage() {
    const data = {};
    return {
        setItem(key, value) {
            data[key] = String(value);
        },
        getItem(key) {
            return Object.prototype.hasOwnProperty.call(data, key) ? data[key] : null;
        }
    };
}

const mockLocalStorage = createMockStorage();
const mockSessionStorage = createMockStorage();

mockLocalStorage.setItem("shared", "Stays after the browser restarts");
mockSessionStorage.setItem("shared", "Gone when this tab closes");

console.log("localStorage:", mockLocalStorage.getItem("shared"));
console.log("sessionStorage:", mockSessionStorage.getItem("shared"));

The storage Event

On a real page, whenever localStorage changes in one tab, the browser fires a storage event in every other open tab from the same origin (not the tab that made the change). This is commonly used to keep multiple open tabs in sync, such as logging every tab out at once. This behavior needs multiple real browser tabs to observe and cannot be demonstrated inside this single-page sandbox.

localStorage vs sessionStorage

Feature localStorage sessionStorage
Persists after the browser closes? Yes No
Shared across tabs of the same origin? Yes No — separate per tab
Cleared automatically when? Only when explicitly removed When the tab is closed
Same interface (setItem, getItem, etc.)? Yes Yes
Typical use case User preferences, saved settings Temporary form data, one-time flags

Common Mistakes with Web Storage

  • Storing an object or array without JSON.stringify(), which silently stores the unhelpful string "[object Object]".
  • Forgetting to convert a stored number or boolean back to its real type after reading it as a string.
  • Storing sensitive data (passwords, tokens) in localStorage, which is readable by any script running on the page.
  • Assuming sessionStorage is shared between tabs — it is not, even for tabs on the same site.
  • Not handling the case where getItem() returns null for a key that was never set.

What this code does: Demonstrates the classic mistake of storing an object without JSON.stringify().

function createMockStorage() {
    const data = {};
    return {
        setItem(key, value) {
            data[key] = String(value);
        },
        getItem(key) {
            return Object.prototype.hasOwnProperty.call(data, key) ? data[key] : null;
        }
    };
}

const mockLocalStorage = createMockStorage();
const user = { name: "Michael" };

// Mistake: forgetting JSON.stringify()
mockLocalStorage.setItem("user", user);
console.log(mockLocalStorage.getItem("user"));   // "[object Object]"

Best Practices for Web Storage

  • Always use JSON.stringify() and JSON.parse() when storing or reading objects and arrays.
  • Never store sensitive information like passwords or authentication tokens in localStorage.
  • Check for null when reading a key that may not exist yet.
  • Use sessionStorage for short-lived, per-tab data, and localStorage for data that should persist across visits.
  • Wrap storage operations in try...catch in production code, since storage can throw if it is full or disabled by the browser.

Quick Summary

  • setItem(), getItem(), removeItem(), and clear() are the core methods shared by both storage objects.
  • getItem() returns null for a missing key instead of throwing an error.
  • Everything is stored as a string — use JSON.stringify()/JSON.parse() for objects and arrays, and convert numbers manually.
  • length and key(index) let you loop through all stored keys.
  • localStorage persists indefinitely; sessionStorage is cleared when the tab closes and is not shared between tabs.
  • A storage event fires in other open tabs when localStorage changes.

Try It Yourself

Modify the code below. Try storing a different object, removing one key while keeping another, or checking what getItem() returns after calling clear().

What this code does: A practice exercise that stores settings as JSON, reads them back, removes a key, and inspects the remaining data.

function createMockStorage() {
    const data = {};
    return {
        setItem(key, value) {
            data[key] = String(value);
        },
        getItem(key) {
            return Object.prototype.hasOwnProperty.call(data, key) ? data[key] : null;
        },
        removeItem(key) {
            delete data[key];
        },
        clear() {
            Object.keys(data).forEach(key => delete data[key]);
        },
        get length() {
            return Object.keys(data).length;
        }
    };
}

const mockLocalStorage = createMockStorage();

const settings = { theme: "dark", fontSize: 16 };
mockLocalStorage.setItem("settings", JSON.stringify(settings));
mockLocalStorage.setItem("username", "Michael");

console.log("Total keys:", mockLocalStorage.length);

const savedSettings = JSON.parse(mockLocalStorage.getItem("settings"));
console.log("Theme:", savedSettings.theme);

mockLocalStorage.removeItem("username");
console.log("Username after removal:", mockLocalStorage.getItem("username"));
Tip: Treat Web Storage as a plain string-only key-value store — always JSON.stringify() objects going in and JSON.parse() them coming out, and reach for sessionStorage instead of localStorage whenever the data truly only needs to last for one tab.

Understanding localStorage and sessionStorage gives you a simple way to persist data on the client side, and pairs naturally with the Fetch API for caching data retrieved from a server.

🧪 Test Your JavaScript Code

Edit the code on the left and click "Run Code" to see the console output on the right.

📝 JavaScript Code
👁 Console Output

Click "Run Code" to see the output here.

Ctrl + Enter to run code Esc to close