I found this article helpful to get me started: Working with IndexedDB  |  Articles  | It recommends the jakearchibald/idb: IndexedDB, but with promises library, which I found intuitive to work with.

  • Using IndexedDB - Web APIs | MDN
  • Should have one object store for each type of data
    • eg. when storing persons and notes, it should have an object store for eeach
    • these stores can be set when creating the database via upgrade
      • you’re only allowed to do it then for database integrity

Create Object store


  • You can pass in a key that is unique as you create the “table”
  • or you can set this which will automatically generate a key
db.createObjectStore('notes', { autoIncrement: true });

this sets the primary key automatically to an incrementing number

db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });

this is similar, but explicitly set id as the identifier field that is filled with incrementing numbers


const objectStore = db.createObjectStore('storeName');
objectStore.createIndex('indexName', 'property', options);
  • unique: true the index doesn’t allow duplicates for this field
  • multiEntry determines how to deal with arrays
    • true: add index for each element
    • otherwise: add single entry containing the array

Best practices

Best Practices for Using IndexedDB  |  Articles  |

Store files as ArrayBuffer

Safari on iOS cannot store Blobs in IndexedDB.

function blobToArrayBuffer(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.addEventListener('loadend', () => {
    reader.addEventListener('error', reject);

Don’t store large, nested objects as a single record

The reason is because when IndexedDB stores an object, it must first create a structured clone of that object, and the structured cloning process happens on the main thread. The larger the object, the longer the blocking time will be.