Browser Data Storage Options
localStorage
Persistent storage that remains until explicitly cleared.
// Store data
localStorage.setItem('username', 'john_doe');
localStorage.setItem('preferences', JSON.stringify({ theme: 'dark', fontSize: 14 }));
// Retrieve data
const username = localStorage.getItem('username'); // 'john_doe'
const preferences = JSON.parse(localStorage.getItem('preferences'));
// Remove item
localStorage.removeItem('username');
// Clear all data
localStorage.clear();Characteristics:
- Persists across browser sessions and restarts
- Storage limit ~5MB
- Synchronous API (can block the main thread)
- Same-origin policy (accessible only from same domain)
- No expiration mechanism
sessionStorage
Similar to localStorage but limited to the current session.
// Store data
sessionStorage.setItem('cart', JSON.stringify([{ id: 1, name: 'Product', qty: 2 }]));
// Retrieve data
const cart = JSON.parse(sessionStorage.getItem('cart'));
// Remove item
sessionStorage.removeItem('cart');
// Clear all session data
sessionStorage.clear();Characteristics:
- Data cleared when the page session ends (tab close)
- Storage limit ~5MB
- Synchronous API
- Same-origin policy
- Separate storage per tab (even for same origin)
Cookies
Small text files stored on the client’s computer.
// Set cookie with expiration and path
document.cookie = "username=john_doe; expires=Fri, 31 Dec 2023 23:59:59 GMT; path=/; SameSite=Strict";
// Read all cookies
const cookies = document.cookie; // Returns all cookies as a single string
// Parse cookies
function getCookie(name) {
  const cookieArr = document.cookie.split(';');
  for (let i = 0; i < cookieArr.length; i++) {
    const cookiePair = cookieArr[i].split('=');
    if (name === cookiePair[0].trim()) {
      return decodeURIComponent(cookiePair[1]);
    }
  }
  return null;
}
// Delete cookie (set expiration in the past)
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;";Characteristics:
- Sent with every HTTP request to the server
- Storage limit ~4KB
- Can set expiration date/time
- Can restrict to specific paths and domains
- Can be made secure (HTTPS only)
- Can be set as HttpOnly (inaccessible to JavaScript)
IndexedDB
Client-side database for larger amounts of structured data.
// Open database
const request = indexedDB.open('MyDatabase', 1);
request.onupgradeneeded = function(event) {
  const db = event.target.result;
  const store = db.createObjectStore('users', { keyPath: 'id' });
  store.createIndex('name', 'name', { unique: false });
};
request.onsuccess = function(event) {
  const db = event.target.result;
  
  // Add data
  const transaction = db.transaction(['users'], 'readwrite');
  const store = transaction.objectStore('users');
  store.add({ id: 1, name: 'John', email: 'john@example.com' });
  
  // Read data
  const getRequest = store.get(1);
  getRequest.onsuccess = function() {
    console.log(getRequest.result);
  };
};Characteristics:
- Asynchronous API (doesn’t block the main thread)
- Supports transactions and indexes
- Storage limit much larger (generally 50-100MB or more)
- Complex API compared to localStorage
- Same-origin policy
Cache API
Part of the Service Worker API, used for storing HTTP responses.
// Open a cache
caches.open('v1').then(cache => {
  // Add resources to cache
  cache.addAll([
    '/index.html',
    '/styles.css',
    '/script.js',
    '/images/logo.png'
  ]);
  
  // Add individual response
  fetch('/api/data')
    .then(response => cache.put('/api/data', response));
});
// Retrieve from cache
caches.match('/index.html')
  .then(response => {
    if (response) {
      return response;
    }
    return fetch('/index.html');
  });Characteristics:
- Designed for offline web applications
- Works with Service Workers
- Stores Response objects
- Asynchronous API (Promise-based)
- Same-origin policy
Web Storage API Events
Listen for storage changes across tabs/windows:
// Listen for changes to localStorage
window.addEventListener('storage', event => {
  console.log('Storage changed:', {
    key: event.key,
    oldValue: event.oldValue,
    newValue: event.newValue,
    url: event.url
  });
});Comparison Table
| Feature | localStorage | sessionStorage | Cookies | IndexedDB | Cache API | 
|---|---|---|---|---|---|
| Persistence | Until cleared | Tab session | Configurable | Until cleared | Until cleared | 
| Size Limit | ~5MB | ~5MB | ~4KB | 50MB+ | Based on disk space | 
| API | Synchronous | Synchronous | Synchronous | Asynchronous | Asynchronous | 
| Complexity | Simple | Simple | Moderate | Complex | Moderate | 
| Auto-sends to server | No | No | Yes | No | No | 
| Best for | Simple persistent data | Temporary session data | Authentication | Structured data | Offline assets | 
Best Practices
- Choose the right storage mechanism for your use case
- Validate and sanitize data before storing
- Handle storage errors (quota exceeded, etc.)
- Don’t store sensitive information in client-side storage
- Implement data expiration for long-term storage
- Use feature detection before using storage APIs
- Consider privacy regulations like GDPR when storing user data
Interview Tips
- Explain the differences between localStorage and sessionStorage
- Describe when cookies are more appropriate than Web Storage
- Discuss the performance implications of synchronous vs asynchronous storage
- Explain how to handle storage limitations and errors
- Describe security considerations for client-side storage
Test Your Knowledge
Take a quick quiz to test your understanding of this topic.