How GoDB.js Simplifies IndexedDB with a Developer‑Friendly API

This article introduces GoDB.js, a TypeScript‑based wrapper for IndexedDB that provides a concise, schema‑aware CRUD API, hides asynchronous connection handling, and offers batch operations, making client‑side data storage in modern web apps much easier.

Programmer DD
Programmer DD
Programmer DD
How GoDB.js Simplifies IndexedDB with a Developer‑Friendly API

Preface

In 2021, when a front‑end application needs to store data in the browser, there are three mainstream solutions: Cookie: existed since ancient times, but its business scenarios are limited. LocalStorage: simple and flexible, but limited to 10 MB and has problems storing JavaScript objects. IndexedDB: a true database with powerful features, yet it has many pitfalls, a cumbersome API, and feels out of place in modern front‑end engineering.

I once built a vocabulary‑learning app with IndexedDB during college, but set the project aside. Recently I revisited the idea, rewrote the wrapper in TypeScript, filled the gaps, and released it as an open‑source library named GoDB.js.

GoDB.js

GoDB

lets you use IndexedDB fluently even if you are not familiar with its API, handling MDN details for you so you can focus on business logic.

The current version is Alpha (0.4.x); do not use it in serious scenarios before the stable 1.0.0 release.

Installation

npm install godb

CDN support will be added in a future release.

Simple Usage

CRUD operations are extremely simple—add, delete, update, and query each require only one line of code:

import GoDB from 'godb';

const testDB = new GoDB('testDB');
const user = testDB.table('user');

const data = { name: 'luke', age: 22 };

user.add(data) // add
  .then(luke => user.get(luke.id)) // get
  .then(luke => user.put({ ...luke, age: 23 })) // update
  .then(luke => user.delete(luke.id)); // delete
Table.get()

, Table.add() and Table.put() return the full record. Table.delete() returns undefined.

Note that put(obj) requires the object to contain an id field; otherwise it behaves like add(obj).

You can also add multiple records at once:

const data = [
  { name: 'luke', age: 22 },
  { name: 'elaine', age: 23 }
];

user.addMany(data)
  .then(() => user.consoleTable());
Table.consoleTable()

prints the table in the console for debugging. It is asynchronous, so you may need await or .then to ensure correct order.

When using addMany, the insertion order follows the order of the input array, and the returned array of IDs matches that order.

Schema

If you want a stricter database structure, you can define a schema. Example:

import GoDB from 'godb';

const schema = {
  user: {
    name: { type: String, unique: true },
    age: Number
  }
};

const testDB = new GoDB('testDB', schema);
const user = testDB.table('user');

const data = { name: 'luke', age: 22 };
user.add(data) // succeeds
  .then(() => user.get({ name: 'luke' })) // can query by non‑id field
  .then(luke => user.add(luke)) // throws because name is unique
  .catch(err => console.error(err));

When a schema is defined, get() and delete() can use indexed fields other than id. Without a schema, GoDB behaves like MongoDB, using an internal _id field.

Using await

All GoDB APIs return promises, so await can make code cleaner, especially inside loops.

import GoDB from 'godb';

const db = new GoDB('testDB', schema);
const user = db.table('user');

async function crud() {
  await user.addMany([
    { name: 'luke', age: 22 },
    { name: 'elaine', age: 23 }
  ]);
  console.log('add user: luke');
  await user.consoleTable();

  const luke = await user.get({ name: 'luke' });
  luke.age = 23;
  await user.put(luke);
  console.log('update: set luke.age to 23');
  await user.consoleTable();

  await user.delete({ name: 'luke' });
  console.log('delete user: luke');
  await user.consoleTable();
}

crud();

API Design

Connecting to the database and to a table are asynchronous operations. Two design approaches were considered:

Design 1 – expose async connection

Most open‑source IndexedDB wrappers require you to open the database and then chain operations, which works but becomes cumbersome in component‑based front‑end frameworks where each component would need to await the connection.

Design 2 – hide async connection

GoDB hides the asynchronous nature of opening the database. Internally it uses a getDB(callback) method and a queue: if the database is not yet connected, operations are queued and executed in FIFO order once the connection succeeds. This allows developers to write natural code without worrying about connection state:

const db = new GoDB('testDB');
const user = db.table('user');

user.add({ name: 'luke', age: 22 })
  .then(luke => console.log(luke));

Advantages: higher performance (single shared connection), cleaner code, and lower mental load for developers. The main drawback is the additional complexity in the library implementation.

Conclusion

GoDB.js provides a developer‑friendly wrapper for IndexedDB, handling schema definition, CRUD, batch operations, and connection management. The project is open‑source on GitHub, and more features (such as an update method and CDN distribution) will be added in future releases.

Visit the project website at godb-js.github.io for documentation.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TypeScriptJavaScriptdatabaseIndexedDB
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.