idb

A tiny, promise-based wrapper around IndexedDB that keeps the native API but drops the event-listener boilerplate.

Library
npm
v8.0.3
7,416 stars
ISC

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
40 /100 Fair
Development Activity 0
Maintenance 0
Community 60
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
83 /100 Excellent
Architecture 85
Code Quality 80
Innovation 88
Learning Curve 85

idb is a ~1.19kB (brotli’d) library by Jake Archibald that mirrors the browser’s IndexedDB API almost exactly, but returns promises instead of firing success/error events. Every method that would normally hand back an IDBRequest resolves or rejects instead, so IndexedDB code can be written with plain async/await rather than nested callbacks.

On top of the promise conversion, idb adds small usability layers: shortcut methods for common single-store operations (get, put, delete, getAll, and their index-scoped equivalents), a tx.done promise and tx.store accessor on transactions, and async-iterator support for cursors so stores and indexes can be looped over with for-await-of. Full TypeScript typings, including a generic DBSchema for typed stores and indexes, ship with the package, and zero runtime dependencies keep it safe to drop into any bundler-based or CDN-based project.

What You Get

  • openDB() and deleteDB() as promise-returning replacements for indexedDB.open/deleteDatabase, with upgrade/blocked/blocking/terminated callbacks
  • Shortcut methods on the database object (get, put, add, delete, clear, getAll, getAllKeys, count) and their *FromIndex equivalents, so single-store operations skip explicit transaction creation
  • tx.done (a promise that resolves when a transaction commits) and tx.store (the sole object store in a single-store transaction), removing common transaction-lifetime bugs
  • Async-iterator support for cursors — for await (const cursor of store) — via a separate with-async-ittr entry point to keep the core bundle small
  • wrap()/unwrap() escape hatches to convert between native IndexedDB objects and idb’s enhanced versions when interoperating with other code
  • Full TypeScript definitions, including a generic DBSchema type for compile-time-checked store names, key paths, and index names

Common Use Cases

  • Offline-first web apps that need structured client-side storage beyond what localStorage or a simple key-value store can offer
  • PWA caching layers that persist API responses, user data, or media alongside the Cache API
  • Building a typed local database schema (stores, indexes, versioned migrations) for a browser application without adopting a heavier ORM
  • Replacing hand-rolled IndexedDB promise wrappers with a small, well-tested, zero-dependency library

Under The Hood

Architecture — idb’s core is a Proxy-based transform in src/wrap-idb-value.ts. The wrap() function checks whether a value is an IDBRequest (in which case it’s promisified directly via promisifyRequest) or one of the proxyable IDB types (IDBDatabase, IDBObjectStore, IDBIndex, IDBCursor, IDBTransaction), in which case it returns a Proxy wrapping that value with idbProxyTraps. The traps intercept property gets to recursively wrap() whatever is returned (so nested calls like db.transaction(…).objectStore(…).get(…) stay wrapped end-to-end), special-case tx.done and tx.store, and unwrap ‘this’ before calling into native methods to avoid ILLEGAL INVOCATION errors. Two WeakMaps (transformCache, reverseTransformCache) cache the wrapped/unwrapped pairs so repeated access to the same object returns the same Proxy (preserving object equality) and so unwrap() can reverse the mapping. src/entry.ts builds openDB/deleteDB on top of this, attaching upgradeneeded/blocked/blocking/terminated listeners to the underlying IDBOpenDBRequest. src/database-extras.ts layers the get/put/delete-style shortcut methods on top of the wrapped database, and src/async-iterators.ts adds Symbol.asyncIterator to cursors/stores/indexes by repeatedly calling continue() and yielding each wrapped cursor.

Tech Stack — The library is 97% TypeScript with zero runtime dependencies, targeting modern browsers only (no IE) and relying on the DOM lib’s IndexedDB type definitions. It’s built with Rollup 4 (@rollup/plugin-typescript, @rollup/plugin-node-resolve, @rollup/plugin-terser) into three consumable outputs declared via package.json’s exports map: an ESM build (build/index.js), a CJS build (build/index.cjs), and a UMD build served directly off jsdelivr for script-tag use. A custom size-report script (lib/size-report.mjs) runs after every build to track the brotli’d bundle size, and the project uses pnpm for dependency management.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers