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);
};
Using Dexie.js (Recommended)
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
| Storage | Capacity | Data Types | Query |
|---|---|---|---|
| IndexedDB | GBs | Any (inc. blobs) | Indexed |
| localStorage | ~5 MB | Strings only | Key only |
| sessionStorage | ~5 MB | Strings only | Key only |
| Cache API | GBs | Request/Response | URL 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
- Use a wrapper library: Dexie, idb, or localForage
- Plan schema carefully: Migrations can be complex
- Handle quota errors: Graceful degradation when full
- Use transactions properly: Group related operations
- 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