Skip to main content

IndexedDB

IndexedDB is a low-level browser API for storing large amounts of structured data, including files and blobs. It's the most powerful client-side storage option and is essential for offline-first and local-first applications.

Key Features

  • Large storage: Gigabytes of data (browser/device dependent)
  • Indexed queries: Fast lookups via indexes
  • Transactions: ACID-compliant operations
  • Async API: Non-blocking operations
  • Structured data: Store objects, arrays, blobs

Basic Operations

// Open database
const request = indexedDB.open('myDatabase', 1);

request.onupgradeneeded = (event) => {
const db = event.target.result;
const store = db.createObjectStore('users', { keyPath: 'id' });
store.createIndex('email', 'email', { unique: true });
};

request.onsuccess = (event) => {
const db = event.target.result;

// Add data
const tx = db.transaction('users', 'readwrite');
const store = tx.objectStore('users');
store.add({ id: 1, name: 'Alice', email: 'alice@example.com' });

// Read data
const getRequest = store.get(1);
getRequest.onsuccess = () => console.log(getRequest.result);
};
import Dexie from 'dexie';

const db = new Dexie('myDatabase');

db.version(1).stores({
users: '++id, email, name',
posts: '++id, userId, title',
});

// CRUD operations
await db.users.add({ name: 'Alice', email: 'alice@example.com' });
const user = await db.users.get(1);
const activeUsers = await db.users.where('active').equals(true).toArray();
await db.users.update(1, { name: 'Alice Smith' });
await db.users.delete(1);

IndexedDB vs Other Storage

StorageCapacityData TypesQuery
IndexedDBGBsAny (inc. blobs)Indexed
localStorage~5 MBStrings onlyKey only
sessionStorage~5 MBStrings onlyKey only
Cache APIGBsRequest/ResponseURL match

What We Like

  • Capacity: Store significant amounts of data
  • Performance: Indexed queries are fast
  • Persistence: Data survives browser restarts
  • Offline support: Essential for offline-first apps
  • Blob storage: Store files, images, videos

What We Don't Like

  • Complex API: Callback-based, verbose without wrappers
  • No SQL: Query capabilities are limited
  • Browser differences: Subtle implementation variations
  • Schema migrations: Version management can be tricky
  • Debugging: Browser DevTools support varies

Best Practices

  1. Use a wrapper library: Dexie, idb, or localForage
  2. Plan schema carefully: Migrations can be complex
  3. Handle quota errors: Graceful degradation when full
  4. Use transactions properly: Group related operations
  5. Consider sync: Combine with service workers for offline

Use Cases

  • Offline-first applications
  • Caching API responses
  • Storing user-generated content
  • Local drafts and autosave
  • PWA data persistence