Skip to content
beginnerPhase 29 · Web Foundations

Local Storage

Use localStorage for client-side data persistence with key-value pairs.

30m
0 problems
Topic Progress0%

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

Practice Problems

0/3solved
Build Local Storage Component

Create a reusable React component implementing Local Storage. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
Local Storage Testing

Write unit and integration tests for Local Storage using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
Local Storage Performance

Optimize Local Storage for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What is the approximate size limit of localStorage?

Question 1 options

2. Why shouldn't you store auth tokens in localStorage?

Question 2 options

3. How do you store an object in localStorage?

Question 3 options

4. Does localStorage sync across browser tabs?

Question 4 options

Flashcards

Question

What is localStorage?

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?

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?

Answer

Use JSON.stringify() to serialize and JSON.parse() to deserialize.

Question

What is Local Storage?

Answer

Local Storage is a key concept in frontend development.

Question

When to use Local Storage?

Answer

Use Local Storage when building production systems that require reliability, scalability, and maintainability.

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