LocalStorage, SessionStorage, and IndexedDB
Alex Chang
Feb 2026
1 tab
// 1. localStorage basics
// Store data
localStorage.setItem('username', 'alex');
localStorage.setItem('theme', 'dark');
// Retrieve data
const username = localStorage.getItem('username'); // 'alex'
// Remove data
localStorage.removeItem('username');
// Clear all
localStorage.clear();
// Check if key exists
if (localStorage.getItem('theme') !== null) {
console.log('Theme is set');
}
// 2. Storing objects (JSON serialization)
const user = {
id: 1,
name: 'Alex',
settings: { theme: 'dark', language: 'en' }
};
// Store
localStorage.setItem('user', JSON.stringify(user));
// Retrieve
const storedUser = JSON.parse(localStorage.getItem('user'));
// 3. Helper functions
const storage = {
set(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (error) {
console.error('Storage error:', error);
return false;
}
},
get(key, defaultValue = null) {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (error) {
console.error('Parse error:', error);
return defaultValue;
}
},
remove(key) {
localStorage.removeItem(key);
},
clear() {
localStorage.clear();
},
keys() {
return Object.keys(localStorage);
},
has(key) {
return localStorage.getItem(key) !== null;
}
};
// Usage
storage.set('user', { name: 'Alex' });
const user = storage.get('user', {});
// 4. Storage with expiration
const storageWithExpiry = {
set(key, value, ttl) {
const now = new Date();
const item = {
value: value,
expiry: ttl ? now.getTime() + ttl : null,
};
localStorage.setItem(key, JSON.stringify(item));
},
get(key) {
const itemStr = localStorage.getItem(key);
if (!itemStr) return null;
const item = JSON.parse(itemStr);
const now = new Date();
if (item.expiry && now.getTime() > item.expiry) {
localStorage.removeItem(key);
return null;
}
return item.value;
}
};
// Usage
storageWithExpiry.set('token', 'abc123', 3600000); // 1 hour
// 5. sessionStorage (same API, different scope)
sessionStorage.setItem('tempData', 'value');
const tempData = sessionStorage.getItem('tempData');
// 6. Storage events (synchronize across tabs)
window.addEventListener('storage', (event) => {
console.log('Storage changed!');
console.log('Key:', event.key);
console.log('Old value:', event.oldValue);
console.log('New value:', event.newValue);
console.log('URL:', event.url);
// Update UI based on changes
if (event.key === 'theme') {
updateTheme(event.newValue);
}
});
// 7. Check storage quota
if ('storage' in navigator && 'estimate' in navigator.storage) {
navigator.storage.estimate().then(({ usage, quota }) => {
console.log(`Using ${usage} bytes of ${quota} bytes.`);
const percentUsed = (usage / quota * 100).toFixed(2);
console.log(`Storage used: ${percentUsed}%`);
});
}
// 8. IndexedDB - structured storage
let db;
// Open database
const request = indexedDB.open('MyDatabase', 1);
request.onerror = () => {
console.error('Database failed to open');
};
request.onsuccess = () => {
db = request.result;
console.log('Database opened successfully');
};
// Create object stores
request.onupgradeneeded = (event) => {
db = event.target.result;
// Create object store
const objectStore = db.createObjectStore('users', {
keyPath: 'id',
autoIncrement: true
});
// Create indexes
objectStore.createIndex('email', 'email', { unique: true });
objectStore.createIndex('name', 'name', { unique: false });
console.log('Database setup complete');
};
// 9. IndexedDB CRUD operations
const dbOperations = {
// Create
async add(storeName, data) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName], 'readwrite');
const objectStore = transaction.objectStore(storeName);
const request = objectStore.add(data);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
},
// Read
async get(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName]);
const objectStore = transaction.objectStore(storeName);
const request = objectStore.get(key);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
},
// Update
async put(storeName, data) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName], 'readwrite');
const objectStore = transaction.objectStore(storeName);
const request = objectStore.put(data);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
},
// Delete
async delete(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName], 'readwrite');
const objectStore = transaction.objectStore(storeName);
const request = objectStore.delete(key);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
},
// Get all
async getAll(storeName) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName]);
const objectStore = transaction.objectStore(storeName);
const request = objectStore.getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
},
// Query by index
async getByIndex(storeName, indexName, value) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName]);
const objectStore = transaction.objectStore(storeName);
const index = objectStore.index(indexName);
const request = index.get(value);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
};
// Usage
async function example() {
// Add user
await dbOperations.add('users', {
name: 'Alex',
email: 'alex@example.com',
age: 30
});
// Get user by ID
const user = await dbOperations.get('users', 1);
// Update user
await dbOperations.put('users', {
id: 1,
name: 'Alex Chen',
email: 'alex@example.com',
age: 31
});
// Get user by email (using index)
const userByEmail = await dbOperations.getByIndex(
'users',
'email',
'alex@example.com'
);
// Get all users
const allUsers = await dbOperations.getAll('users');
// Delete user
await dbOperations.delete('users', 1);
}
1 file · javascript
Explain with highlit
Web storage APIs persist data in the browser. I use localStorage for permanent client-side storage across sessions. The sessionStorage API stores data for single sessions that clears when tabs close. Both provide simple key-value storage with 5-10MB limits. IndexedDB offers larger storage (50MB+) with transactional database features. Storage events synchronize data across tabs. JSON serialization stores complex objects. IndexedDB supports indexes, cursors, and queries for structured data. Storage quotas prevent abuse. Understanding storage options enables offline functionality and better UX.