npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rmacklin/idb

v2.1.3-pr77

Published

IndexedDB but with promises

Readme

IndexedDB Promised

This is a tiny library that mirrors IndexedDB, but replaces the weird IDBRequest objects with promises, plus a couple of other small changes.

Installation

If you're using Rollup/Webpack or similar:

npm install idb

Then in your JS:

import idb from 'idb';

await idb.open(…);

Or include the script as it is, and idb will exist on the global scope.

Examples

Keyval Store

This is very similar to localStorage, but async. If this is all you need, you may be interested in idb-keyval, you can always upgrade to this library later.

const dbPromise = idb.open('keyval-store', 1, upgradeDB => {
  upgradeDB.createObjectStore('keyval');
});

const idbKeyval = {
  get(key) {
    return dbPromise.then(db => {
      return db.transaction('keyval')
        .objectStore('keyval').get(key);
    });
  },
  set(key, val) {
    return dbPromise.then(db => {
      const tx = db.transaction('keyval', 'readwrite');
      tx.objectStore('keyval').put(val, key);
      return tx.complete;
    });
  },
  delete(key) {
    return dbPromise.then(db => {
      const tx = db.transaction('keyval', 'readwrite');
      tx.objectStore('keyval').delete(key);
      return tx.complete;
    });
  },
  clear() {
    return dbPromise.then(db => {
      const tx = db.transaction('keyval', 'readwrite');
      tx.objectStore('keyval').clear();
      return tx.complete;
    });
  },
  keys() {
    return dbPromise.then(db => {
      const tx = db.transaction('keyval');
      const keys = [];
      const store = tx.objectStore('keyval');

      // This would be store.getAllKeys(), but it isn't supported by Edge or Safari.
      // openKeyCursor isn't supported by Safari, so we fall back
      (store.iterateKeyCursor || store.iterateCursor).call(store, cursor => {
        if (!cursor) return;
        keys.push(cursor.key);
        cursor.continue();
      });

      return tx.complete.then(() => keys);
    });
  }
};

Usage

idbKeyval.set('foo', {hello: 'world'});

// logs: {hello: 'world'}
idbKeyval.get('foo').then(val => console.log(val));

Set of objects

Imagine we had a set of objects like…

{
  "id": 123456,
  "data": {"foo": "bar"}
}

Upgrading existing DB

const dbPromise = idb.open('keyval-store', 2, upgradeDB => {
  // Note: we don't use 'break' in this switch statement,
  // the fall-through behaviour is what we want.
  switch (upgradeDB.oldVersion) {
    case 0:
      upgradeDB.createObjectStore('keyval');
    case 1:
      upgradeDB.createObjectStore('objs', {keyPath: 'id'});
  }
});

Adding

dbPromise.then(db => {
  const tx = db.transaction('objs', 'readwrite');
  tx.objectStore('objs').put({
    id: 123456,
    data: {foo: "bar"}
  });
  return tx.complete;
});

Getting all

dbPromise.then(db => {
  return db.transaction('objs')
    .objectStore('objs').getAll();
}).then(allObjs => console.log(allObjs));

Getting by ID

dbPromise.then(db => {
  return db.transaction('objs')
    .objectStore('objs').get(123456);
}).then(obj => console.log(obj));

Limitations

Transaction lifetime

An IDB transaction will auto-close if it doesn't have anything to do once microtasks have been processed. As a result, this works fine:

dbPromise.then(async db => {
  const tx = db.transaction('keyval', 'readwrite');
  const store = tx.objectStore('keyval');
  const val = await store.get('counter') || 0;
  store.put(val + 1, 'counter');
  return tx.complete;
});

But this doesn't:

dbPromise.then(async db => {
  const tx = db.transaction('keyval', 'readwrite');
  const store = tx.objectStore('keyval');
  const val = await store.get('counter') || 0;
  // The transaction will auto-close while the fetch is in-progress
  const newVal = await fetch('/increment?val=' + val)
  store.put(newVal, 'counter');
  return tx.complete;
});

Promise issues in older browsers

Some older browsers don't handle promises properly, which causes issues if you do more than one thing in a transaction:

dbPromise.then(async db => {
  const tx = db.transaction('keyval', 'readwrite');
  const store = tx.objectStore('keyval');
  const val = await store.get('counter') || 0;
  // In some older browsers, the transaction closes here.
  // Meaning this next line fails:
  store.put(val + 1, 'counter');
  return tx.complete;
});

All modern browsers have fixed this. Test your browser.

You can work around this in some versions of Firefox by using a promise polyfill that correctly uses microtasks, such as es6-promise.

API

idb

This is your entry point to the API. It's exposed to the global scope unless you're using a module system such as browserify, in which case it's the exported object.

idb.open(name, version, upgradeCallback)

This method returns a promise that resolves to a DB.

name and version behave as they do in indexedDB.open.

upgradeCallback is called if version is greater than the version last opened. It's similar to IDB's onupgradeneeded. The callback receives an instance of UpgradeDB.

idb.open('keyval-store', 2, upgradeDB => {
  // Note: we don't use 'break' in this switch statement,
  // the fall-through behaviour is what we want.
  switch (upgradeDB.oldVersion) {
    case 0:
      upgradeDB.createObjectStore('keyval');
    case 1:
      upgradeDB.createObjectStore('stuff', {keyPath: ''});
  }
}).then(db => console.log("DB opened!", db));

idb.delete(name)

Behaves like indexedDB.deleteDatabase, but returns a promise.

idb.delete('keyval-store').then(() => console.log('done!'));

DB

Properties:

  • Same as equivalent properties on an instance of IDBDatabase:
    • name
    • version
    • objectStoreNames

Methods:

  • close - as idbDatabase.close
  • transaction - as idbDatabase.transaction, but returns a Transaction

UpgradeDB

As DB, except:

Properties:

  • transaction - this is a property rather than a method. It's a Transaction representing the upgrade transaction
  • oldVersion - the previous version of the DB seen by the browser, or 0 if it's new

Methods:

  • createObjectStore - as idbDatabase.createObjectStore, but returns an ObjectStore
  • deleteObjectStore - as idbDatabase.deleteObjectStore

Transaction

Properties:

  • complete - a promise. Resolves when transaction completes, rejects if transaction aborts or errors
  • Same as equivalent properties on an instance of IDBTransaction:
    • objectStoreNames
    • mode

Methods:

  • abort - as idbTransaction.abort
  • objectStore - as idbTransaction.objectStore, but returns an ObjectStore
idb.open('keyval-store', 1, upgradeDB => {
  switch (upgradeDB.oldVersion) {
    case 0:
      upgradeDB.createObjectStore('keyval');
  }
}).then(db => {
  const tx = db.transaction('keyval', 'readwrite');
  tx.objectStore('keyval').put('hello', 'world');
  return tx.complete;
}).then(() => console.log("Done!"));

ObjectStore

Properties:

  • Same as equivalent properties on an instance of IDBObjectStore:
    • name
    • keyPath
    • indexNames
    • autoIncrement

Methods:

  • Same as equivalent methods on an instance of IDBObjectStore, but returns a promise that resolves/rejects based on operation success/failure:
    • put
    • add
    • delete
    • clear
    • get
    • getAll
    • getAllKeys
    • count
  • Same as equivalent methods on an instance of IDBObjectStore, but returns a promise that resolves with a Cursor:
    • openCursor
    • openKeyCursor
  • deleteIndex - as idbObjectStore.deleteIndex
  • Same as equivalent methods on an instance of IDBObjectStore, but returns an Index:
    • createIndex
    • index
  • iterateCursor - see below
  • iterateKeyCursor - see below

iterateCursor & iterateKeyCursor

Due to the microtask issues in some browsers, iterating over a cursor using promises doesn't always work:

const tx = db.transaction('stuff');
tx.objectStore('stuff').openCursor().then(function cursorIterate(cursor) {
  if (!cursor) return;
  console.log(cursor.value);
  return cursor.continue().then(cursorIterate);
});
tx.complete.then(() => console.log('done'));

So in the mean time, iterateCursor and iterateKeyCursor map to openCursor & openKeyCursor, take identical arguments, plus an additional callback that receives an IDBCursor, so the above example becomes:

const tx = db.transaction('stuff');
tx.objectStore('stuff').iterateCursor(cursor => {
  if (!cursor) return;
  console.log(cursor.value);
  cursor.continue();
});
tx.complete.then(() => console.log('done'));

The intent is to remove iterateCursor and iterateKeyCursor from the library once browsers support promises and microtasks correctly.

Index

Properties:

  • Same as equivalent properties on an instance of IDBIndex:
    • name
    • keyPath
    • multiEntry
    • unique

Methods:

  • Same as equivalent methods on an instance of IDBIndex, but returns a promise that resolves/rejects based on operation success/failure:
    • get
    • getKey
    • getAll
    • getAllKeys
    • count
  • Same as equivalent methods on an instance of IDBIndex, but returns a promise that resolves with a Cursor:
    • openCursor
    • openKeyCursor
  • iterateCursor - as objectStore.iterateCursor but over the index
  • iterateKeyCursor - as objectStore.iterateKeyCursor but over the index

Cursor

Properties:

  • Same as equivalent properties on an instance of IDBCursor:
    • direction
    • key
    • primaryKey
    • value

Methods:

  • Same as equivalent methods on an instance of IDBCursor, but returns a promise that resolves/rejects based on operation success/failure:
    • update
    • delete
  • Same as equivalent methods on an instance of IDBCursor, but returns a promise that resolves with a Cursor:
    • advance
    • continue
    • continuePrimaryKey