Idb
IndexedDB, but with promises
Install / Use
/learn @jakearchibald/IdbREADME
IndexedDB with usability.
This is a tiny (~1.19kB brotli'd) library that mostly mirrors the IndexedDB API, but with small improvements that make a big difference to usability.
Installation
Using npm
npm install idb
Then, assuming you're using a module-compatible system (like webpack, Rollup etc):
import { openDB, deleteDB, wrap, unwrap } from 'idb';
async function doDatabaseStuff() {
const db = await openDB(…);
}
Directly in a browser
Using the modules method directly via jsdelivr:
<script type="module">
import { openDB, deleteDB, wrap, unwrap } from 'https://cdn.jsdelivr.net/npm/idb@8/+esm';
async function doDatabaseStuff() {
const db = await openDB(…);
}
</script>
Using external script reference
<script src="https://cdn.jsdelivr.net/npm/idb@8/build/umd.js"></script>
<script>
async function doDatabaseStuff() {
const db = await idb.openDB(…);
}
</script>
A global, idb, will be created, containing all exports of the module version.
Changes
See details of (potentially) breaking changes.
Browser support
This library targets modern browsers, as in Chrome, Firefox, Safari, and other browsers that use those engines, such as Edge. IE is not supported.
API
openDB
This method opens a database, and returns a promise for an enhanced IDBDatabase.
const db = await openDB(name, version, {
upgrade(db, oldVersion, newVersion, transaction, event) {
// …
},
blocked(currentVersion, blockedVersion, event) {
// …
},
blocking(currentVersion, blockedVersion, event) {
// …
},
terminated() {
// …
},
});
name: Name of the database.version(optional): Schema version, orundefinedto open the current version.upgrade(optional): Called if this version of the database has never been opened before. Use it to specify the schema for the database. This is similar to theupgradeneededevent in plain IndexedDB.db: An enhancedIDBDatabase.oldVersion: Last version of the database opened by the user.newVersion: Whatever new version you provided.transaction: An enhanced transaction for this upgrade. This is useful if you need to get data from other stores as part of a migration.event: The event object for the associatedupgradeneededevent.
blocked(optional): Called if there are older versions of the database open on the origin, so this version cannot open. This is similar to theblockedevent in plain IndexedDB.currentVersion: Version of the database that's blocking this one.blockedVersion: The version of the database being blocked (whatever version you provided toopenDB).event: The event object for the associatedblockedevent.
blocking(optional): Called if this connection is blocking a future version of the database from opening. This is similar to theversionchangeevent in plain IndexedDB.currentVersion: Version of the open database (whatever version you provided toopenDB).blockedVersion: The version of the database that's being blocked.event: The event object for the associatedversionchangeevent.
terminated(optional): Called if the browser abnormally terminates the connection, but not on regular closures like callingdb.close(). This is similar to thecloseevent in plain IndexedDB.
deleteDB
Deletes a database.
await deleteDB(name, {
blocked() {
// …
},
});
name: Name of the database.blocked(optional): Called if the database already exists and there are open connections that don’t close in response to a versionchange event, the request will be blocked until they all close.currentVersion: Version of the database that's blocking the delete operation.event: The event object for the associated 'versionchange' event.
unwrap
Takes an enhanced IndexedDB object and returns the plain unmodified one.
const unwrapped = unwrap(wrapped);
This is useful if, for some reason, you want to drop back into plain IndexedDB. Promises will also be converted back into IDBRequest objects.
wrap
Takes an IDB object and returns a version enhanced by this library.
const wrapped = wrap(unwrapped);
This is useful if some third party code gives you an IDBDatabase object and you want it to have the features of this library.
General enhancements
Once you've opened the database the API is the same as IndexedDB, except for a few changes to make things easier.
Firstly, any method that usually returns an IDBRequest object will now return a promise for the result.
const store = db.transaction(storeName).objectStore(storeName);
const value = await store.get(key);
Promises & throwing
The library turns all IDBRequest objects into promises, but it doesn't know in advance which methods may return promises.
As a result, methods such as store.put may throw instead of returning a promise.
If you're using async functions, there's no observable difference.
Transaction lifetime
TL;DR: Do not await other things between the start and end of your transaction, otherwise the transaction will close before you're done.
An IDB transaction auto-closes if it doesn't have anything left do once microtasks have been processed. As a result, this works fine:
const tx = db.transaction('keyval', 'readwrite');
const store = tx.objectStore('keyval');
const val = (await store.get('counter')) || 0;
await store.put(val + 1, 'counter');
await tx.done;
But this doesn't:
const tx = db.transaction('keyval', 'readwrite');
const store = tx.objectStore('keyval');
const val = (await store.get('counter')) || 0;
// This is where things go wrong:
const newVal = await fetch('/increment?val=' + val);
// And this throws an error:
await store.put(newVal, 'counter');
await tx.done;
In this case, the transaction closes while the browser is fetching, so store.put fails.
IDBDatabase enhancements
Shortcuts to get/set from an object store
It's common to create a transaction for a single action, so helper methods are included for this:
// Get a value from a store:
const value = await db.get(storeName, key);
// Set a value in a store:
await db.put(storeName, value, key);
The shortcuts are: get, getKey, getAll, getAllKeys, count, put, add, delete, and clear. Each method takes a storeName argument, the name of the object store, and the rest of the arguments are the same as the equivalent IDBObjectStore method.
Shortcuts to get from an index
The shortcuts are: getFromIndex, getKeyFromIndex, getAllFromIndex, getAllKeysFromIndex, and countFromIndex.
// Get a value from an index:
const value = await db.getFromIndex(storeName, indexName, key);
Each method takes storeName and indexName arguments, followed by the rest of the arguments from the equivalent IDBIndex method.
IDBTransaction enhancements
tx.store
If a transaction involves a single store, the store property will reference that store.
const tx = db.transaction('whatever');
const store = tx.store;
If a transaction involves multiple stores, tx.store is undefined, you need to use tx.objectStore(storeName) to get the stores.
tx.done
Transactions have a .done promise which resolves when the transaction completes successfully, and otherwise rejects with the transaction error.
const tx = db.transaction(storeName, 'readwrite');
await Promise.all([
tx.store.put('bar', 'foo'),
tx.store.put('world', 'hello'),
tx.done,
]);
If you're writing to the database, tx.done is the signal that everything was successfully committed to the database. However, it's still beneficial to await the individual operations, as you'll see the error that caused the transaction to fail.
IDBCursor enhancements
Cursor advance methods (advance, continue, continuePrimaryKey) return a promise for the cursor, or null if there are no further values to provide.
let cursor = await db.transaction(storeName).store.openCursor();
while (cursor) {
console.log(cursor.key, cursor.value);
cursor = await cursor.continue();
}
Async iterators
You can iterate over stores, indexes, and cursors:
const tx = db.transaction(storeName);
for await (const cursor of tx.store) {
// …
}
Each yielded object is an IDBCursor. You can optionally use the advance methods to skip items (within an async iterator they return void):
const tx = db.transaction(storeName);
for await (const cursor of tx.store) {
console.log(cursor.value);
// Skip the next item
cursor.advance(2);
}
If you don't manually advance the cursor, cursor.continue() is called for you.
Stores and indexes also have an iterate method which has the same signature as openCursor, but returns an async iterator:
const ind
Related Skills
node-connect
326.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
80.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
326.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
80.4kCommit, push, and open a PR
