javascript 273 lines · 1 tab

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.


Related snips

javascript
// Creating a Promise
const myPromise = new Promise((resolve, reject) => {
  const success = true;

  setTimeout(() => {
    if (success) {

Promises and async/await patterns for asynchronous JavaScript

javascript promises async-await
by Alex Chang 1 tab
javascript
import { Controller } from "@hotwired/stimulus"
import Mousetrap from "mousetrap"

export default class extends Controller {
  connect() {
    // Global shortcuts

Keyboard shortcuts with Stimulus and Mousetrap

stimulus javascript ux
by Jordan Lee 2 tabs
javascript
// Get canvas and context
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// 1. Basic shapes
// Rectangle (filled)

Canvas API for graphics and animations

canvas javascript graphics
by Alex Chang 1 tab
javascript
// Basic event listener
const button = document.getElementById('myButton');

button.addEventListener('click', function(event) {
  console.log('Button clicked!');
  console.log('Event type:', event.type);

Event handling and event delegation patterns in JavaScript

javascript events event-delegation
by Alex Chang 1 tab
javascript
// Basic GET request
fetch('https://api.example.com/users')
  .then(response => {
    console.log('Status:', response.status);
    console.log('OK:', response.ok);
    return response.json();

Fetch API for HTTP requests and AJAX communication

javascript fetch api
by Alex Chang 1 tab
erb
<turbo-stream action="set_title">
  <template><%= "Inbox (#{@unread_count})" %></template>
</turbo-stream>

Turbo Streams: update document title with a custom action

rails hotwire turbo
by Henry Kim 2 tabs

Share this code

Here's the card — post it anywhere.

LocalStorage, SessionStorage, and IndexedDB — share card
Link copied