A Minimalistic Wrapper for IndexedDB
Dexie is a lightweight JavaScript wrapper around IndexedDB that removes the complexity of the native API while maintaining its performance benefits. Instead of dealing with verbose transaction callbacks and event handlers, you get a promise-based interface with intuitive query methods and automatic transaction management. With nearly 1 million weekly downloads, it's trusted by production applications including WhatsApp Web.
The library exists because IndexedDB's native API is notoriously difficult to work with—requiring boilerplate for basic CRUD operations, manual transaction handling, and callback-based error management. Dexie provides a declarative schema definition system, chainable query methods, and reactive live queries that automatically update your UI when data changes. It's not trying to be a full ORM or replace server-side databases; it's focused on making browser-based structured storage practical.
Developers building progressive web apps, offline-first applications, or any browser-based tool that needs to store significant amounts of structured data will find Dexie essential. It's particularly valuable for dashboards with heavy client-side filtering, collaborative tools that need local caching, or mobile web apps that must function without connectivity. The optional Dexie Cloud addon extends this with real-time sync and authentication, but the core library works entirely client-side with no backend dependencies.
Dexie strikes a balance between simplicity and power. You get indexed queries, compound indexes, full-text search capabilities, and bulk operations that are optimized at the IndexedDB level. The API surface is small enough to learn quickly but expressive enough to handle complex data scenarios without dropping down to raw IndexedDB calls.
import { Dexie } from 'dexie';
// Define database schema
class TaskDatabase extends Dexie {
tasks;
constructor() {
super('TaskDB');
this.version(1).stores({
tasks: '++id, title, status, dueDate, [status+dueDate]'
});
this.tasks = this.table('tasks');
}
}
const db = new TaskDatabase();
// Bulk insert tasks
await db.tasks.bulkAdd([
{ title: 'Review PRs', status: 'pending', dueDate: '2024-01-15', tags: ['dev'] },
{ title: 'Write docs', status: 'pending', dueDate: '2024-01-16', tags: ['docs'] },
{ title: 'Deploy hotfix', status: 'completed', dueDate: '2024-01-14', tags: ['ops'] }
]);
// Query with compound index for efficient filtering
const urgentPending = await db.tasks
.where('[status+dueDate]')
.between(['pending', '2024-01-01'], ['pending', '2024-01-16'])
.toArray();
console.log('Urgent tasks:', urgentPending);
// Update with partial changes
await db.tasks
.where('status').equals('pending')
.modify({ status: 'in-progress' });
// Live query for reactive UI (works with React/Vue/Svelte hooks)
const liveTasksObservable = db.liveQuery(() =>
db.tasks.where('status').equals('in-progress').toArray()
);
liveTasksObservable.subscribe(tasks => {
console.log('Active tasks updated:', tasks.length);
});
// Transaction for atomic multi-table operations
await db.transaction('rw', db.tasks, async () => {
const task = await db.tasks.get(1);
await db.tasks.update(1, {
status: 'completed',
completedAt: new Date().toISOString()
});
});Offline-first note-taking or document editors: Store user documents locally with full-text search across content, automatic versioning through IndexedDB's object store capabilities, and instant filtering by tags or metadata. Changes sync when connectivity returns, and liveQuery() keeps the UI reactive across browser tabs.
E-commerce product catalogs with client-side filtering: Download thousands of products to IndexedDB on initial load, then provide instant search and faceted filtering without server round-trips. Compound indexes on category+price enable performant range queries, while bulk operations handle catalog updates efficiently.
Task management and project tracking tools: Store tasks, projects, and user data locally for instant load times and offline access. Use transactions to ensure related updates (like moving a task between projects) stay atomic, and leverage hooks to trigger side effects like updating cached aggregations.
Analytics dashboards caching API responses: Cache large datasets from backend APIs to provide instant visualization updates. Use Dexie's querying to slice data by date ranges or dimensions without re-fetching, and clear/refresh cache based on staleness policies.
Collaborative drawing or design tools: Store canvas states, version history, and user actions locally. Dexie Cloud's realm-based access control enables sharing artboards between team members with proper permissions, while local storage ensures the app remains responsive during complex operations.
npm install dexiepnpm add dexiebun add dexie