Web applications have multiple options for storing user information locally and these methods vary greatly in capacity and behavior. The Indexed Database API, commonly referred to as indexedDB, is a NoSQL database and supported by all major browsers. In today’s tutorial we will implement a simple interface for using indexedDB, which you can then add to a progressive web application (PWA) to create an offline storage.
Pros and Cons
Before we get into the weeds of implementation, let us first investigate the reasons for choosing indexedDB.
Pros
- Allows adding offline storage to web applications
- Very liberal storage limit
- NoSQL implementation fits many use cases and works well with JSON data
- Can be used to store multimedia like images and video (1
- Good libraries exist to make implementation quick
- Asynchronous API
Cons
- Must migrate when changes occur in schema
- Storage is local and synchronization is necessary between devices
1) Check per browser support for blob objects; if not supported you must store media in base64 format.
Based on your application needs, indexedDB may be a good fit for you, but it comes with certain assumptions. You get a large storage for storing complex structures, but will have to deal with schema migrations and more implementation complexity. For very simple use cases you might want to consider localStorage, sessionStorage or cookies instead.
Requirements
- Node.js install here ↗
- Any javascript IDE of your choice examples ↗
Implementation
In this tutorial we will build a simple javascript (ES6) database class using indexedDB. We will use Dexie.js, which is a library that makes working with indexedDB very simple.
We assume you are adding a database to an existing project. However, if you are starting this tutorial without any existing project, first create a project directory, then run npm init
to initialize a new project.
1. Add dexie as a dependency
1 | npm install dexie |
We will use dexie as a way to define our database schema and to execute various operations on the database.
2. Create db.js
file
This file will be our database implementation
3. Import dexie
In db.js
, import dexie as a dependency:
1 | import Dexie from 'dexie'; |
4. Declare the Database class
1 | import Dexie from 'dexie'; |
5. Declare database schema
Before declaring your schema, think carefully what type of information you plan to store in the database and what are the stored properties by which you are going to look up information. Any indexed properties need to be defined in the schema declaration.
1 | import Dexie from 'dexie'; |
You may store information not specified in the schema, but since it will not indexed, you cannot query data by that property. For example, given the above schema definition, I might store a pet
object such as this one:
1 | { |
In essence, your schema should contain the properties you are going to use to lookup information. If you are familiar with relational databases where you must explicitly define each stored property, you will notice this to be a big difference between relational schemas and indexedDB.
As with other databases, you have multiple options for choosing your method for setting primary keys. This topic is way beyond the depth of this article, but if you need a refresher, you may read more about setting primary keys with dexie here.
6. Create basic CRUD methods
1 | import Dexie from 'dexie'; |
Dexie includes many operations for working with the stored data. The examples above are simply basic operations to get you started. For more in-depth examples, study the full documentation here.
7. Use database in your application.
You now have a fully implemented database interface for storing user’s data on local machine. The following is an example of how to use the database in your app. It is worthwhile to note that these operations are asynchronous, so we must wait for the operation to complete before referencing the data using then
. If you prefer async
/await
syntax over promises, it should work here also.
1 | import Database from './db' |
Happy Coding!