localStorage API
localStorage provides key-value storage that persists across browser sessions.
Basic Operations
// Set item
localStorage.setItem('theme', 'dark');
localStorage.setItem('user', JSON.stringify({ name: 'Alice', age: 25 }));
// Get item
const theme = localStorage.getItem('theme'); // 'dark'
const user = JSON.parse(localStorage.getItem('user')); // {name: 'Alice', age: 25}
// Remove item
localStorage.removeItem('theme');
// Clear all
localStorage.clear();
// Get length
const count = localStorage.length;
// Get key by index
const key = localStorage.key(0);
Bracket Notation
// Alternative syntax (like an object)
localStorage['theme'] = 'dark';
const theme = localStorage['theme'];
delete localStorage['theme'];
Storage Event
// Listen for changes (from other tabs/windows)
window.addEventListener('storage', (event) => {
console.log('Key:', event.key);
console.log('Old value:', event.oldValue);
console.log('New value:', event.newValue);
console.log('URL:', event.url);
});
Common Use Cases
// Theme preference
localStorage.setItem('theme', 'dark');
// Form draft
localStorage.setItem('draft-form', JSON.stringify(formData));
// User preferences
localStorage.setItem('preferences', JSON.stringify({
language: 'en',
notifications: true,
fontSize: 14
}));
// Cache API responses
localStorage.setItem('cache-users', JSON.stringify({
data: users,
timestamp: Date.now()
}));
When to Use localStorage
localStorage is useful for persisting non-sensitive data on the client.
Good Use Cases
| Use Case | Why |
|---|---|
| Theme preferences | User preference, not sensitive |
| Language settings | Persistent across sessions |
| Form drafts | Save unsaved work |
| UI state | Sidebar collapsed, grid view |
| Cached data | Reduce API calls |
| Onboarding state | Track tutorial progress |
Bad Use Cases
| Use Case | Why |
|---|---|
| Authentication tokens | Vulnerable to XSS |
| Sensitive data | Visible in DevTools |
| Large data | 5-10MB limit |
| Frequent writes | Synchronous API, blocks main thread |
| Server-side state | Not synchronized with server |
Implementation Example
// Safe localStorage wrapper
const Storage = {
get(key, defaultValue = null) {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (e) {
console.error('localStorage get error:', e);
return defaultValue;
}
},
set(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (e) {
console.error('localStorage set error:', e);
return false;
}
},
remove(key) {
localStorage.removeItem(key);
},
clear() {
localStorage.clear();
}
};
// Usage
Storage.set('theme', 'dark');
const theme = Storage.get('theme', 'light');
Data Serialization
// Always serialize complex types
localStorage.setItem('user', JSON.stringify(user));
const user = JSON.parse(localStorage.getItem('user'));
// Handle dates
const data = {
createdAt: new Date().toISOString() // Convert to string
};
localStorage.setItem('data', JSON.stringify(data));
const stored = JSON.parse(localStorage.getItem('data'));
stored.createdAt = new Date(stored.createdAt); // Convert back
localStorage Limitations
localStorage has several limitations you need to understand.
Limitations
| Limit | Details |
|---|---|
| Size | ~5-10MB per origin |
| Synchronous | Blocks main thread |
| String only | Must serialize objects |
| No expiration | Manual cleanup required |
| Same origin | Isolated by protocol + domain + port |
| Not accessible in workers | Use IndexedDB instead |
Size Limit
// Check available space
function getStorageSize() {
let total = 0;
for (let key in localStorage) {
if (localStorage.hasOwnProperty(key)) {
total += localStorage[key].length * 2; // UTF-16
}
}
return total;
}
try {
localStorage.setItem('test', 'x'.repeat(5 * 1024 * 1024));
} catch (e) {
console.error('Storage full:', e.name); // QuotaExceededError
}
Synchronous API
// This blocks the main thread!
localStorage.setItem('large', hugeString);
// Better: Use requestIdleCallback or Web Worker
function saveLargeData(data) {
requestIdleCallback(() => {
localStorage.setItem('large', JSON.stringify(data));
});
}
Cross-Tab Synchronization
// Only syncs via storage event
window.addEventListener('storage', (e) => {
if (e.key === 'user') {
const newUser = JSON.parse(e.newValue);
updateUserUI(newUser);
}
});
// Does NOT sync in same tab!
// Must use custom events or state management
Alternative: IndexedDB
// For larger, async storage
const request = indexedDB.open('MyDB', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
db.createObjectStore('users', { keyPath: 'id' });
};
request.onsuccess = (event) => {
const db = event.target.result;
const tx = db.transaction('users', 'readwrite');
const store = tx.objectStore('users');
store.add({ id: 1, name: 'Alice' });
};
Performance Tips
// Batch operations
const updates = { theme: 'dark', lang: 'en', notifications: true };
Object.entries(updates).forEach(([key, value]) => {
localStorage.setItem(key, JSON.stringify(value));
});
// Use sessionStorage for temporary data
sessionStorage.setItem('temp', data);
// Use IndexedDB for large datasets
// Use localStorage for small preferences only
Quiz
1. What is the approximate size limit of localStorage?
2. Why shouldn't you store auth tokens in localStorage?
3. How do you store an object in localStorage?
4. Does localStorage sync across browser tabs?
Flashcards
Question
What is localStorage?
Click to reveal answer
Answer
Browser storage for key-value pairs that persists across sessions. Limited to ~5-10MB, synchronous, string-only.
Question
Why is localStorage not secure for auth tokens?
Click to reveal answer
Answer
It's accessible to JavaScript, making it vulnerable to XSS attacks that can steal tokens.
Question
How do you store complex objects in localStorage?
Click to reveal answer
Answer
Use JSON.stringify() to serialize and JSON.parse() to deserialize.
Revision Notes
Key Takeaways
- 1. localStorage persists across browser sessions
- 2. Limited to ~5-10MB and synchronous API
- 3. Always serialize objects with JSON.stringify/parse
- 4. Not secure for sensitive data (vulnerable to XSS)
- 5. Use sessionStorage for temporary data
Interview Tips
- • Know the difference between localStorage and sessionStorage
- • Understand why localStorage is not secure for auth tokens
- • Know the size limitations and alternatives (IndexedDB)
- • Be familiar with the storage event for cross-tab sync
Cheat Sheet
localStorage Cheat Sheet
API Methods:
- setItem(key, value)
- getItem(key)
- removeItem(key)
- clear()
- length
- key(index)
Limitations:
- ~5-10MB per origin
- Synchronous (blocks main thread)
- String only (use JSON)
- No expiration
- Same origin only
Good For:
- Theme preferences
- Language settings
- Form drafts
- UI state
- Cached data
Bad For:
- Auth tokens (XSS risk)
- Sensitive data
- Large datasets
- Server-side state
Best Practice:
Use JSON.stringify/parse for objects