Handling IndexedDB Upgrade Version Conflict
Tags: indexeddb, javascript
Published: 2019-10-18 13:50:24

---
title: Handling IndexedDB Upgrade Version Conflict
published: true
description: 
tags: indexeddb,javascript
---

IndexedDB is a large-scale, NoSQL storage system. It lets you store almost anything in the user's browser (google uses this technology inside google docs extensively).

But with great power comes great responsibility. When working with traditional ( server side ) databases you are in control of the database
schema and deploying new versions or rolling back to previous ones.

However, when the database is in client control, doing those things reliably is not easy.

## The Issue

The issue that I'm going to address in this blog post is about the case when the user has multiple tabs (or windows ) open of the same site. Since all tabs are using the same underlying database, there is a possibility that a user when opening the new tab of the same site receives the new version of the application (just pushed to production) and that version brings changes to the database schema.

When that happens new tab has a newer version of the database and code running in that tab (since this is the newest version of the application ) is made to work with the new DB schema, however in the previous tab old version of the code works with different `DB schema` and if we leave that code running it can corrupt the database.

## The Solution

Luckily creators of the indexedDB have foreseen this problem early in the design phase of the technology itself and they have given us some tools to handle such conflicts.

There are two events that we can listen to when we connect to the database:

- The `onversionchange` event handler handles the version change event, fired when a database structure change was requested elsewhere ( new tab/ window)
- The `onblocked` event handles the scenario when we try to upgrade the database (change to the new schema) but the database is still in use somewhere (another tab/window) even after the `onversionchange` event is sent.

I'm going to use these two events to safely upgrade the database.

These are the required steps:

- Deploy the new version of the database ( increase the `version` number)
- Close the database connection in **_tab 1_** by listening to `onversionchange`
- Force the user to reload **_tab 1_** by creating the overlay and disabling any interaction with the site.

Here is how it looks with three chromium windows on the same site:
![indexedDB upgrade process animation](https://raw.githubusercontent.com/ivandotv/blog-posts/master/posts/indexedDB-upgrade-conflict/assets/indexeddb-upgrade-process.gif)

## The Code

```js
//database version starts at 1
const version = 1
const dbName = "testing"
let db = null

// open the database connection
let openRequest = indexedDB.open(dbName, version)

openRequest.onsuccess = function(event) {
  // store the result of opening the database connection in the db variable.
  db = openRequest.result

  // add listener to handle database version change
  db.onversionchange = function() {
    //!important when version change is detected close the database immediately
    db.close() // hint:1
    // instruct the user to reload the page via popup
    // and block the interaction
    launchPopup($newVersionPopupContent)
  }
}
```

To trigger the `onversionchange` event listener all we need to do is increase the `version` variable that is passed to the `indexedDB.open` method.

Code at `hint:1` ( `db.close`) is very important, if we do not close the database connection when the `onversionchange` event is triggered new code ( **tab 2** ) will also be blocked.

Remember, `onversionchange` is not triggered in the new tab ( new db - **tab 2**) this event will be triggered in all **tabs with the old db**.

## Concluson

This is my solution to safely handle IndexedDB upgrade conflict. Some people might not like forcing the user to reload the page but that is the safest way, and it is highly unlikely that the user will be in the situation when two different application versions are running in the browser in the first place, but hey it can happen. It happened to me. So just make them reload.

I have made the demo code available via [github](https://github.com/ivandotv/indexeddb-upgrade-conflict-demo).

If you want to learn more about IndexedDB Google web developer portal has a [great intro to the subject](https://developers.google.com/web/ilt/pwa/working-with-indexeddb).