Skip to content

JavaScript Storage APIs

Mattscreative edited this page Feb 21, 2026 · 1 revision

JavaScript Storage APIs Guide

Table of Contents


Introduction

JavaScript provides several ways to store data in the browser. Each has different use cases and characteristics.


localStorage

localStorage stores data with no expiration time. Data persists even after closing the browser.

Basic Operations

// Set item
localStorage.setItem('username', 'Alice');
localStorage.setItem('preferences', JSON.stringify({ theme: 'dark', lang: 'en' }));

// Get item
const username = localStorage.getItem('username');
const prefs = JSON.parse(localStorage.getItem('preferences'));

// Remove item
localStorage.removeItem('username');

// Clear all
localStorage.clear();

// Check if key exists
localStorage.getItem('username') !== null;  // true/false

Properties and Methods

// Length
console.log(localStorage.length);  // Number of items

// Get key by index
console.log(localStorage.key(0));  // First key

// Iterate over all items
for (let i = 0; i < localStorage.length; i++) {
    const key = localStorage.key(i);
    const value = localStorage.getItem(key);
    console.log(key, value);
}

// Using forEach (modern)
Object.keys(localStorage).forEach(key => {
    console.log(key, localStorage.getItem(key));
});

Storage Events

// Listen for changes in localStorage (on other tabs)
window.addEventListener('storage', (event) => {
    console.log('Key changed:', event.key);
    console.log('Old value:', event.oldValue);
    console.log('New value:', event.newValue);
    console.log('URL:', event.url);
});

Limitations

// Storage limits (approximately 5-10MB)
console.log('Approximate quota:', 5 * 1024 * 1024, 'bytes');

// Only stores strings
localStorage.setItem('number', 42);        // Stored as "42"
localStorage.setItem('boolean', true);    // Stored as "true"
localStorage.setItem('array', [1, 2, 3]); // Stored as "1,2,3"

// Solution: Use JSON
localStorage.setItem('data', JSON.stringify({
    number: 42,
    boolean: true,
    array: [1, 2, 3]
}));

sessionStorage

sessionStorage stores data for one session (until the tab is closed).

Basic Operations

// Same API as localStorage
sessionStorage.setItem('tempData', 'value');
const value = sessionStorage.getItem('tempData');
sessionStorage.removeItem('tempData');
sessionStorage.clear();

// Data is cleared when tab/window closes
sessionStorage.setItem('sessionData', 'This will be gone when tab closes');

Use Cases

// Remember form progress during a session
function saveFormProgress(field, value) {
    sessionStorage.setItem(`form_${field}`, value);
}

// Store sensitive data that shouldn't persist
sessionStorage.setItem('authToken', 'temporary-token');

// Temporary calculations
sessionStorage.setItem('calculation', JSON.stringify({ result: 42 }));

IndexedDB

IndexedDB is a powerful client-side database for storing large amounts of structured data.

Opening a Database

// Open database
const request = indexedDB.open('MyDatabase', 1);

// Handle success
request.onsuccess = (event) => {
    const db = event.target.result;
    console.log('Database opened');
};

// Handle errors
request.onerror = (event) => {
    console.error('Database error:', event.target.error);
};

// Handle upgrades (schema changes)
request.onupgradeneeded = (event) => {
    const db = event.target.result;
    
    // Create object store
    if (!db.objectStoreNames.contains('users')) {
        const userStore = db.createObjectStore('users', { keyPath: 'id', autoIncrement: true });
        
        // Create indexes
        userStore.createIndex('name', 'name', { unique: false });
        userStore.createIndex('email', 'email', { unique: true });
    }
};

Adding Data

function addUser(user) {
    const request = indexedDB.open('MyDatabase', 1);
    
    request.onsuccess = (event) => {
        const db = event.target.result;
        const transaction = db.transaction(['users'], 'readwrite');
        const store = transaction.objectStore('users');
        
        const addRequest = store.add(user);
        
        addRequest.onsuccess = () => {
            console.log('User added:', addRequest.result);
        };
    };
}

addUser({ name: 'Alice', email: 'alice@example.com', age: 25 });

Reading Data

function getUser(id) {
    return new Promise((resolve, reject) => {
        const request = indexedDB.open('MyDatabase', 1);
        
        request.onsuccess = (event) => {
            const db = event.target.result;
            const transaction = db.transaction(['users'], 'readonly');
            const store = transaction.objectStore('users');
            
            const getRequest = store.get(id);
            
            getRequest.onsuccess = () => {
                resolve(getRequest.result);
            };
            
            getRequest.onerror = () => {
                reject(getRequest.error);
            };
        };
    });
}

// Get all users
function getAllUsers() {
    return new Promise((resolve, reject) => {
        const request = indexedDB.open('MyDatabase', 1);
        
        request.onsuccess = (event) => {
            const db = event.target.result;
            const transaction = db.transaction(['users'], 'readonly');
            const store = transaction.objectStore('users');
            
            const getAllRequest = store.getAll();
            
            getAllRequest.onsuccess = () => {
                resolve(getAllRequest.result);
            };
        };
    });
}

Updating Data

function updateUser(id, updates) {
    const request = indexedDB.open('MyDatabase', 1);
    
    request.onsuccess = (event) => {
        const db = event.target.result;
        const transaction = db.transaction(['users'], 'readwrite');
        const store = transaction.objectStore('users');
        
        // First get the user
        const getRequest = store.get(id);
        
        getRequest.onsuccess = () => {
            const user = getRequest.result;
            const updatedUser = { ...user, ...updates };
            store.put(updatedUser);
        };
    };
}

Deleting Data

function deleteUser(id) {
    const request = indexedDB.open('MyDatabase', 1);
    
    request.onsuccess = (event) => {
        const db = event.target.result;
        const transaction = db.transaction(['users'], 'readwrite');
        const store = transaction.objectStore('users');
        
        store.delete(id);
    };
}

// Clear all users
function clearUsers() {
    const request = indexedDB.open('MyDatabase', 1);
    
    request.onsuccess = (event) => {
        const db = event.target.result;
        const transaction = db.transaction(['users'], 'readwrite');
        const store = transaction.objectStore('users');
        
        store.clear();
    };
}

Using with Promises (Wrapper)

class IndexedDBWrapper {
    constructor(dbName, version, stores) {
        this.dbName = dbName;
        this.version = version;
        this.stores = stores;
    }
    
    open() {
        return new Promise((resolve, reject) => {
            const request = indexedDB.open(this.dbName, this.version);
            
            request.onupgradeneeded = (event) => {
                const db = event.target.result;
                this.stores.forEach(store => {
                    if (!db.objectStoreNames.contains(store.name)) {
                        const objectStore = db.createObjectStore(store.name, store.options);
                        store.indexes?.forEach(index => {
                            objectStore.createIndex(index.name, index.keyPath, index.options);
                        });
                    }
                });
            };
            
            request.onsuccess = () => resolve(request.result);
            request.onerror = () => reject(request.error);
        });
    }
    
    async get(storeName, key) {
        const db = await this.open();
        return new Promise((resolve, reject) => {
            const transaction = db.transaction(storeName, 'readonly');
            const store = transaction.objectStore(storeName);
            const request = store.get(key);
            request.onsuccess = () => resolve(request.result);
            request.onerror = () => reject(request.error);
        });
    }
    
    async getAll(storeName) {
        const db = await this.open();
        return new Promise((resolve, reject) => {
            const transaction = db.transaction(storeName, 'readonly');
            const store = transaction.objectStore(storeName);
            const request = store.getAll();
            request.onsuccess = () => resolve(request.result);
            request.onerror = () => reject(request.error);
        });
    }
    
    async add(storeName, data) {
        const db = await this.open();
        return new Promise((resolve, reject) => {
            const transaction = db.transaction(storeName, 'readwrite');
            const store = transaction.objectStore(storeName);
            const request = store.add(data);
            request.onsuccess = () => resolve(request.result);
            request.onerror = () => reject(request.error);
        });
    }
    
    async put(storeName, data) {
        const db = await this.open();
        return new Promise((resolve, reject) => {
            const transaction = db.transaction(storeName, 'readwrite');
            const store = transaction.objectStore(storeName);
            const request = store.put(data);
            request.onsuccess = () => resolve(request.result);
            request.onerror = () => reject(request.error);
        });
    }
    
    async delete(storeName, key) {
        const db = await this.open();
        return new Promise((resolve, reject) => {
            const transaction = db.transaction(storeName, 'readwrite');
            const store = transaction.objectStore(storeName);
            const request = store.delete(key);
            request.onsuccess = () => resolve();
            request.onerror = () => reject(request.error);
        });
    }
}

Cookies

Cookies are small pieces of data sent between browser and server.

Setting Cookies

// Basic cookie
document.cookie = "username=Alice";
document.cookie = "theme=dark";
document.cookie = "session=abc123; max-age=3600";  // Expires in 1 hour

// With all options
document.cookie = "token=xyz789; " +
    "expires=" + new Date(Date.now() + 86400000).toUTCString() + "; " +
    "path=/; " +
    "domain=example.com; " +
    "secure; " +
    "samesite=strict";

Reading Cookies

// Get all cookies
console.log(document.cookie);

// Parse cookies
function getCookie(name) {
    const nameEQ = name + "=";
    const cookies = document.cookie.split(';');
    
    for (let cookie of cookies) {
        cookie = cookie.trim();
        if (cookie.indexOf(nameEQ) === 0) {
            return cookie.substring(nameEQ.length);
        }
    }
    return null;
}

console.log(getCookie('username'));
console.log(getCookie('theme'));

Deleting Cookies

// Delete by setting expiration to past
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

Comparison

Feature localStorage sessionStorage IndexedDB Cookies
Capacity ~5-10MB ~5-10MB Large (50MB+) ~4KB
Data Type Strings only Strings only Any Strings
Sync/Async Sync Sync Async Sync
Expiration Never Tab close Manual Manual
Server Access No No No Yes
Performance Fast Fast Slower Slow

Practical Examples

Theme Switcher with localStorage

class ThemeSwitcher {
    constructor() {
        this.theme = localStorage.getItem('theme') || 'light';
        this.applyTheme();
    }
    
    toggle() {
        this.theme = this.theme === 'light' ? 'dark' : 'light';
        this.applyTheme();
        localStorage.setItem('theme', this.theme);
    }
    
    applyTheme() {
        document.body.classList.remove('light', 'dark');
        document.body.classList.add(this.theme);
    }
}

const themeSwitcher = new ThemeSwitcher();

Form Auto-Save with sessionStorage

class FormAutoSave {
    constructor(formId, key) {
        this.form = document.getElementById(formId);
        this.key = key;
        this.load();
        this.setupListeners();
    }
    
    setupListeners() {
        this.form.addEventListener('input', (e) => {
            this.save();
        });
    }
    
    save() {
        const data = new FormData(this.form);
        const obj = Object.fromEntries(data);
        sessionStorage.setItem(this.key, JSON.stringify(obj));
    }
    
    load() {
        const saved = sessionStorage.getItem(this.key);
        if (saved) {
            const data = JSON.parse(saved);
            Object.entries(data).forEach(([key, value]) => {
                const input = this.form.elements[key];
                if (input) input.value = value;
            });
        }
    }
    
    clear() {
        sessionStorage.removeItem(this.key);
    }
}

Offline Data with IndexedDB

class OfflineStore {
    constructor() {
        this.dbName = 'OfflineApp';
        this.dbVersion = 1;
    }
    
    async init() {
        return new Promise((resolve, reject) => {
            const request = indexedDB.open(this.dbName, this.dbVersion);
            
            request.onupgradeneeded = (event) => {
                const db = event.target.result;
                
                if (!db.objectStoreNames.contains('cache')) {
                    const cacheStore = db.createObjectStore('cache', { keyPath: 'url' });
                    cacheStore.createIndex('timestamp', 'timestamp', { unique: false });
                }
            };
            
            request.onsuccess = () => resolve(request.result);
            request.onerror = () => reject(request.error);
        });
    }
    
    async cacheResponse(url, response) {
        const data = {
            url,
            response: await response.clone().json(),
            timestamp: Date.now()
        };
        
        const db = await this.init();
        const tx = db.transaction('cache', 'readwrite');
        tx.objectStore('cache').put(data);
    }
    
    async getCached(url) {
        const db = await this.init();
        return new Promise((resolve) => {
            const tx = db.transaction('cache', 'readonly');
            const request = tx.objectStore('cache').get(url);
            
            request.onsuccess = () => resolve(request.result);
        });
    }
}

User Preferences with localStorage

class UserPreferences {
    constructor() {
        this.defaults = {
            theme: 'light',
            language: 'en',
            notifications: true,
            fontSize: 'medium'
        };
        this.prefs = this.load();
    }
    
    load() {
        const saved = localStorage.getItem('preferences');
        return saved ? { ...this.defaults, ...JSON.parse(saved) } : this.defaults;
    }
    
    save() {
        localStorage.setItem('preferences', JSON.stringify(this.prefs));
    }
    
    get(key) {
        return this.prefs[key];
    }
    
    set(key, value) {
        this.prefs[key] = value;
        this.save();
        this.applyPreference(key, value);
    }
    
    applyPreference(key, value) {
        switch (key) {
            case 'theme':
                document.body.classList.toggle('dark', value === 'dark');
                break;
            case 'fontSize':
                document.body.style.fontSize = { small: '14px', medium: '16px', large: '18px' }[value];
                break;
        }
    }
}

Clone this wiki locally