Library / SDK
dumbmatter/fakeIndexedDB avatar
dumbmatter/fakeIndexedDB

fake-indexeddb and running IndexedDB code under Node without a browser

A pure JS in-memory implementation of the IndexedDB API

699 stars80 forksJavaScriptApache-2.0

At a glance

What is it?
fake-indexeddb is a pure JavaScript in-memory implementation of the IndexedDB API, and its main use is testing IndexedDB-dependent code in Node.js. It behaves like IndexedDB except that data is not persisted to disk, and the interesting edges are around global scope, the structuredClone polyfill that jsdom still needs, and how you reset state between tests.
Who is it for?
fake-indexeddb fits a JavaScript or TypeScript project whose code touches IndexedDB and whose test suite runs in Node, and it removes the need to run a browser in CI to exercise a storage path. It is the wrong tool for verifying real persistence, since data is not written to disk, and it is the wrong tool if your production browser behaviour depends on a detail the implementation has not matched.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

IndexedDB semantics, minus the disk

fake-indexeddb is described as a pure JS in-memory implementation of the IndexedDB API, and the whole point is stated in one sentence: functionally, it works exactly like IndexedDB except data is not persisted to disk.

That is a precise and useful claim, and it explains the project better than a longer description would. IndexedDB is a large, awkward API with a request and event model, an upgrade transaction, object stores, indexes, cursors and key ranges, and a lot of application code depends on the exact behaviour of all of it. Reimplementing that in memory, once, means every project that needs to test it does not have to.

The alternative approach is a DOM-like environment such as jsdom, or a real browser, inside the test runner. The cost of that approach can be a slower, heavier test suite. fake-indexeddb is a dependency and a setup import instead.

The repository layout shows a project with real engineering in it. There is a `src/` directory, a `lib/` directory, an `auto/` directory for the global scope entry point, a `test/` directory, `types.d.ts` and `auto.d.ts` for the TypeScript declarations, a `jest.config.js` at the root, a `.babelrc`, a `.husky/` directory for git hooks, a `pnpm-workspace.yaml` and a `pnpm-lock.yaml`, a `bin/` directory, and a `TODO` file.

The package manifest is ESM-first with a CommonJS fallback. The package is `fake-indexeddb` at version 6.2.6, the `type` is `module`, the main entry is `./build/cjs/index.js` and the module entry is `./build/esm/index.js`, and the exports map has separate `import` and `require` conditions for the root, the `./auto` subpath and a long list of `./lib/...` subpaths for the individual classes, each with an import and a require target.

The auto import is a global scope change, and that is the first decision

There are two ways to wire the implementation in, and the difference is whether you touch the global scope.

The easiest way to use it is to import `fake-indexeddb/auto`, which will put all the IndexedDB variables in the global scope. Both `import` and `require` are supported, and the examples in the documentation are all `import`.

js
import "fake-indexeddb/auto";

var request = indexedDB.open("test", 3);

Alternatively, you can explicitly import the individual IndexedDB variables, which leaves the globals alone:

js
import {
    indexedDB,
    IDBCursor,
    IDBCursorWithValue,
    IDBDatabase,
    IDBFactory,
    IDBIndex,
    IDBKeyRange,
    IDBObjectStore,
    IDBOpenDBRequest,
    IDBRequest,
    IDBTransaction,
    IDBVersionChangeEvent,
} from "fake-indexeddb";

And like any imported variable, you can rename it if you want, for instance if you don't want to conflict with the built-in IndexedDB variables:

js
import {
    indexedDB as fakeIndexedDB,
} from "fake-indexeddb";

The choice matters more than it looks. The auto import means your production code, which was written against the browser's globals, runs unmodified in the test, which is the point of the exercise. The explicit import means the code under test has to be told which implementation to use, which is more code and more coupling, but it also means two implementations can coexist in one process.

The renaming trick is the useful middle case. When a test needs to compare a fake database against a real one, or when a module in the dependency graph opens a connection through the global while the code under test uses an injected instance, aliasing the import keeps the two apart without a global mutation.

There is one more thing the explicit import list tells you. The classes are named with an `IDB` prefix, but the internal implementation classes in the export map are named `FDB`, as in `FDBFactory`, `FDBDatabase` and `FDBCursor`. The `IDB` names are the spec names, and the `FDB` names are the fake ones, which is a naming convention worth knowing about when you are reading the source.

Dexie and wrappers depend on the import order

The section on Dexie and other IndexedDB API wrappers is the most practically useful part of the documentation, because it is where the auto import can bite.

If you import `fake-indexeddb/auto` before importing `dexie`, it should work:

js
import "fake-indexeddb/auto";
import Dexie from "dexie";

const db = new Dexie("MyDatabase");

The same likely holds true for other IndexedDB API wrappers like idb.

The alternative, if you don't want to modify the global scope, is to explicitly pass the objects to Dexie:

js
import Dexie from "dexie";
import { indexedDB, IDBKeyRange } from "fake-indexeddb";

const db = new Dexie("MyDatabase", { indexedDB: indexedDB, IDBKeyRange: IDBKeyRange });

So there are two workable strategies, and the second one is not a workaround, it is a design. If your codebase already creates its Dexie instance with injected dependencies, the explicit path is the natural one, because nothing about your production code changes. If your code calls `new Dexie("MyDatabase")` with no arguments, the auto import must come first, and the ordering becomes a rule your team has to remember.

That ordering sensitivity is a real cost of the global approach, and it is worth noting that it is not specific to Dexie. Any library that captures the global at module load time will capture whichever implementation was in place when it was first imported, and a module import order that changes between your app and your test file is a class of bug that produces confusing failures rather than obvious ones.

The library does not provide a way to make this order independent. The choice is global mutation with an ordering rule, or explicit injection.

Jest setup, and the structuredClone gap that jsdom still has

For Jest there are two routes, one per scope of application.

To use fake-indexeddb in a single Jest test suite, require `fake-indexeddb/auto` at the beginning of the test file. To use it on all Jest tests without having to include it in each file, add the auto setup script to the `setupFiles` in your Jest config:

json
{
    "setupFiles": [
        "fake-indexeddb/auto"
    ]
}

The `setupFiles` route is the one to prefer for a project that has more than a couple of test files, since the per-file import is the kind of thing that gets forgotten in the one file that needed it.

The jsdom section is the sharpest edge in the whole project. As of version 5, fake-indexeddb no longer includes a `structuredClone` polyfill. This mostly affects old environments like unsupported versions of Node.js, but it also affects jsdom, which is often used with Jest and other testing frameworks.

There are a few ways to work around this. You could include your own `structuredClone` polyfill by installing core-js and importing its polyfill before you use fake-indexeddb:

js
import "core-js/stable/structured-clone";
import "fake-indexeddb/auto";

Or you could manually include the Node.js `structuredClone` implementation in a jsdom environment, by subclassing the jsdom environment and assigning the global:

js
// FixJSDOMEnvironment.ts

import JSDOMEnvironment from 'jest-environment-jsdom';

export default class FixJSDOMEnvironment extends JSDOMEnvironment {
  constructor(...args: ConstructorParameters<typeof JSDOMEnvironment>) {
    super(...args);

    this.global.structuredClone = structuredClone;
  }
}

and then pointing the Jest config at it:

js
// jest.config.js

const config = {
  testEnvironment: './FixJSDOMEnvironment.ts',
};

module.exports = config;

The documentation closes this section with the hope that a future version of jsdom will no longer require these workarounds. Until then, a project on jsdom carries an extra dependency and a custom environment class, and the order of the two imports in the core-js case matters in the same way the Dexie order does.

This is the single most important thing to check before adopting the package, because it determines whether your test setup is one import or three.

Resetting between tests and simulating a database close

Two utilities exist for the two things a test suite usually needs beyond the API itself.

For isolation, if you are keeping your tests completely isolated you might want to reset the state of the mocked indexedDB, and you can do this by creating a new instance of `IDBFactory`, which lets you have a totally fresh start:

js
import "fake-indexeddb/auto";
import { IDBFactory } from "fake-indexeddb";

// Whenever you want a fresh indexedDB
indexedDB = new IDBFactory();

Note the assignment to the bare `indexedDB` identifier. That is a global write, which is the same trade as the auto import, and it means this reset pattern only works in the global configuration.

For event coverage, an `IDBDatabase` will fire a `"close"` event when closed for abnormal reasons, such as the user manually deleting databases in DevTools, and if you want to simulate this event for test coverage you can use `forceCloseDatabase()`:

js
import { forceCloseDatabase } from "fake-indexeddb";

db.addEventListener("close", () => {
    console.log("Forcibly closed!");
});

That second one is the more interesting capability, because the close event is a real edge case in production code. A browser tab whose database is deleted in DevTools, or a mobile browser reclaiming storage, will fire it, and application code that opens a connection on a closed database will throw. Being able to trigger that path in a test is worth having, and it is the kind of thing that is painful to reproduce against a real browser.

Neither of these utilities is part of the IndexedDB specification, so they are additions rather than reimplementations, and the distinction matters when you are deciding whether a test that uses them is testing your code or testing the fake.

TypeScript types are borrowed from the platform, on purpose

The TypeScript story has a decision in it that is worth understanding before you rely on it.

As of version 4, fake-indexeddb includes TypeScript types. As you can see in types.d.ts, it's just using TypeScript's built-in IndexedDB types, rather than generating types from the fake-indexeddb code base. The stated reason is for compatibility with your application code that may already be using TypeScript's IndexedDB types, so if something different were used for fake-indexeddb, it could lead to spurious type errors.

That is a good reason, and it has a known cost, which the documentation states plainly. In theory this could lead to other errors if there are differences between TypeScript's IndexedDB types and fake-indexeddb's API, but currently the author is not aware of any difference, and issue 23 is linked for more discussion.

So the types are a compatibility layer rather than a description of the implementation. If the fake has a method the platform types do not declare, your code will not type check against it, and if the platform declares something the fake does not implement, your code will type check and then fail at run time. The documentation says it is not aware of any such difference, which is a statement about the current state rather than a guarantee.

The licence is Apache-2.0, and the repository carries a `LICENSE` file alongside a `CHANGELOG.md`, a `CONTRIBUTING.md` and the `TODO` file. The releases are frequent: v6.2.4 on 2025-10-17, v6.2.5 on 2025-11-07, and v6.2.6 on 2026-10-16, with the last push on the same day as the newest release.

One thing the project does not attempt is persistence. Because data is not written to disk, a test that starts a fresh Node process starts with an empty database, and a test that wants to verify a round trip through storage has to model that persistence itself.

Editorial conclusion

fake-indexeddb fits a JavaScript or TypeScript project whose code touches IndexedDB and whose test suite runs in Node, and it removes the need to run a browser in CI to exercise a storage path. It is the wrong tool for verifying real persistence, since data is not written to disk, and it is the wrong tool if your production browser behaviour depends on a detail the implementation has not matched. Before adopting, check three things: whether your test environment is jsdom, because as of version 5 the package no longer ships a structuredClone polyfill and jsdom needs one brought in separately, whether you want the globals or the explicit imports, since the auto import changes the global scope while the named import does not, and how you will reset state between tests, because a new IDBFactory is the documented way to get a fresh database. The code is Apache-2.0, the last push was on 2026-10-16, and the current version is 6.2.6 from the same day.

Frequently asked questions

What is fake-indexeddb and what is it for?

It is a pure JS in-memory implementation of the IndexedDB API, and its main use is testing IndexedDB-dependent code in Node.js. Functionally it works exactly like IndexedDB except data is not persisted to disk.

How do I install and use fake-indexeddb?

Install it with `npm install --save-dev fake-indexeddb`, then import `fake-indexeddb/auto` to put all the IndexedDB variables in the global scope, or import the individual variables such as `indexedDB` and `IDBKeyRange` from `fake-indexeddb` if you do not want to modify the global scope.

Why does fake-indexeddb not work with jsdom?

As of version 5 the package no longer includes a `structuredClone` polyfill, which mostly affects old Node.js versions but also affects jsdom. You can work around it by importing the core-js `core-js/stable/structured-clone` polyfill before fake-indexeddb, or by subclassing the jsdom environment and assigning `this.global.structuredClone`.

How do I reset fake-indexeddb between tests?

Create a new instance of `IDBFactory`, which gives you a totally fresh start, for example `indexedDB = new IDBFactory();`. The package also exports `forceCloseDatabase()` so you can simulate the abnormal close event on an `IDBDatabase` for test coverage.

Does fake-indexeddb ship TypeScript types?

As of version 4 it does, but they are TypeScript's built-in IndexedDB types rather than types generated from the fake-indexeddb code base. The reason given is compatibility with application code that already uses the platform types, and the documentation notes this could in theory hide differences between the platform types and the implementation.

Official sources

  1. dumbmatter/fakeIndexedDB on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dumbmatter-fakeindexeddb.svg)](https://hysenlabs.com/projects/dumbmatter-fakeindexeddb)

Was this useful?