fake-indexeddb review
fake-indexeddb 6.2.5 is an in-memory JavaScript implementation of the browser IndexedDB API for tests that run under Node. Importing `fake-indexeddb/auto` installs IndexedDB globals, while named exports let a test inject its own factory and key-range object. The current release adds `handleEvent` and capture support to its event layer and fixes transaction-timing edge cases. It never writes a database to disk. Its README reports 1,369 of 1,653 relevant IndexedDB Web Platform Tests passing, or 82.8%, so browser coverage still matters for behavior outside the common path.
fake-indexeddb 6.2.5 installed in 0.7 seconds, used 1 MB, and produced 0 audit findings in our sandbox, making it a cheap Node test dependency for ordinary IndexedDB flows. Keep real-browser coverage because the project reports 82.8% of its relevant Web Platform Tests passing and does not persist data to disk.
We installed it
| Install | ✓ · 0.7s | 3 packages on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · ESM package with exports map |
| Browser | 14.8 KB | gzipped (55.7 KB minified), bundled with esbuild |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does fake-indexeddb install cleanly?
Yes. In a fresh container with an empty cache, npm install fake-indexeddb finished in 0.7s, leaving 3 packages and 1 MB on disk. npm audit reported no known vulnerabilities.
How much does fake-indexeddb add to a browser bundle?
14.8 KB gzipped (55.7 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does fake-indexeddb work with both ESM and CommonJS?
Yes. Both import 'fake-indexeddb' and require('fake-indexeddb') worked in Node 22 in our run. The package is published as ESM with an exports map.
Does fake-indexeddb include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
fake-indexeddb or indexeddbshim: which should you use?
indexeddbshim: Use it when an older environment needs IndexedDB behavior backed by WebSQL rather than an in-memory Node test double. fake-indexeddb 6.2.5 installed in 0.7 seconds, used 1 MB, and produced 0 audit findings in our sandbox, making it a cheap Node test dependency for ordinary IndexedDB flows.
When should you not use fake-indexeddb?
Your test must prove persistence across processes or restarts. The README states that this implementation keeps data in memory and does not persist it to disk.
Use it if
- Your Node test suite needs to exercise real IndexedDB requests, transactions, indexes, cursors, and upgrade callbacks without launching a browser.
- Application code already uses Dexie or idb and can receive an IndexedDB factory explicitly or through test-only globals.
- Each test can start from a new `IDBFactory`, which gives deterministic database state without filesystem cleanup.
- You need both CommonJS and ESM test runners; our sandbox loaded 6.2.5 through `require()` and `import`.
- Your test must prove persistence across processes or restarts. The README states that this implementation keeps data in memory and does not persist it to disk.
- A release depends on browser-specific quota, origin isolation, storage eviction, worker behavior, or DevTools deletion. The project's comparison omits worker and cross-origin tests that are irrelevant to Node.
- You need full conformance for rare IndexedDB timing and error paths. Version 6.2.5 passes 82.8% of the relevant Web Platform Test set listed by the project, below every browser in that table.
- Your Jest setup uses jsdom without a working `structuredClone`. Version 5 removed that polyfill, and the README tells affected suites to supply one or patch the jsdom environment.
- You only need a friendlier API over the browser's real IndexedDB. `idb` or Dexie wraps IndexedDB, while fake-indexeddb replaces the storage implementation for tests.
Setup reality
We installed fake-indexeddb 6.2.5 in a fresh Node 22 Bookworm sandbox. npm finished in 0.7 seconds and left 3 packages using 1 MB on disk. The package itself is 708 KB unpacked with 0 direct and 0 peer dependencies. npm audit found 0 known vulnerabilities. It requires Node 18 or newer and includes TypeScript declarations.
Choose the import style before tests start. fake-indexeddb/auto writes indexedDB, IDBKeyRange, and the other IndexedDB constructors onto the global object. Named imports avoid that mutation and work well with Dexie dependency injection. Our checks loaded the ESM package with both import and require() through its exports map.
State survives for the life of the in-memory factory. Create new IDBFactory() between tests that need isolation, close open database handles, and await transaction completion before asserting. Deleting a database can block while another connection remains open, just as the IndexedDB contract specifies. forceCloseDatabase() can trigger the nonstandard abnormal-close path for a targeted test.
The browser bundle measured 55.7 KB minified and 14.8 KB gzipped in our esbuild check, but shipping it to users defeats its main purpose. Keep it in development dependencies. Node 18 supplies structuredClone; older jsdom environments may hide or omit it, so add the README's polyfill or custom environment before importing fake-indexeddb/auto. Run a smaller set of browser tests for quota, workers, persistence, and timing-sensitive production paths.
Patterns
Install it only for tests install-test-double
npm install --save-dev fake-indexeddbVersion 6.2.5 requires Node 18 or newer. It is an in-memory test implementation, so production browser code should use the platform's IndexedDB object.
Register IndexedDB globals before application imports register-globals
import 'fake-indexeddb/auto';
import { startApp } from './app.js';
startApp();The auto entry mutates the global object. Import it before modules that read `indexedDB` during evaluation.
Inject the implementation without changing globals inject-factory
import { indexedDB, IDBKeyRange } from 'fake-indexeddb';
import Dexie from 'dexie';
const db = new Dexie('test-db', { indexedDB, IDBKeyRange });Dexie accepts both objects in its constructor. This keeps the fake scoped to one database instance.
Create a store during a version upgrade open-database
const request = indexedDB.open('catalog', 1);
request.onupgradeneeded = () => {
const db = request.result;
db.createObjectStore('books', { keyPath: 'isbn' });
};
const db = await new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});Schema changes belong in `onupgradeneeded`. Opening a higher version while another connection stays open can trigger the normal blocked-upgrade behavior.
Wait for a write transaction to finish write-record
const tx = db.transaction('books', 'readwrite');
tx.objectStore('books').put({ isbn: '978-1', title: 'Test Book' });
await new Promise((resolve, reject) => {
tx.oncomplete = resolve;
tx.onerror = () => reject(tx.error);
tx.onabort = () => reject(tx.error);
});A successful request does not mean the whole transaction committed. Assert durable transaction state after `oncomplete`.
Convert an IndexedDB request to a promise read-record
const tx = db.transaction('books', 'readonly');
const request = tx.objectStore('books').get('978-1');
const book = await new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});A missing key resolves with `undefined`; it does not reject the request.
Read through a unique index query-index
const store = db.transaction('books').objectStore('books');
const request = store.index('by_title').get('Test Book');
request.onsuccess = () => expect(request.result.isbn).toBe('978-1');Create `by_title` inside an upgrade transaction before using it. Index constraints are checked when writes run.
Collect rows from a bounded cursor iterate-cursor
const rows = [];
const request = db.transaction('books').objectStore('books')
.openCursor(IDBKeyRange.lowerBound('978-1'));
await new Promise((resolve, reject) => {
request.onerror = () => reject(request.error);
request.onsuccess = () => {
const cursor = request.result;
if (!cursor) return resolve();
rows.push(cursor.value);
cursor.continue();
};
});Call `continue()` inside the success handler. The final success event carries a null result and ends iteration.
Give each test a fresh factory reset-between-tests
import { IDBFactory } from 'fake-indexeddb';
beforeEach(() => {
globalThis.indexedDB = new IDBFactory();
});A new factory removes all in-memory databases owned by the previous factory. Resetting globals can conflict with concurrently running tests in the same process.
Delete a test database after closing handles delete-database
db.close();
const request = indexedDB.deleteDatabase('catalog');
await new Promise((resolve, reject) => {
request.onsuccess = resolve;
request.onerror = () => reject(request.error);
request.onblocked = () => reject(new Error('database connection still open'));
});An open connection can block deletion. Close every handle created by the test before awaiting the request.
Test an abnormal close handler force-close-event
import { forceCloseDatabase } from 'fake-indexeddb';
const closed = new Promise((resolve) => db.addEventListener('close', resolve));
forceCloseDatabase(db);
await closed;`forceCloseDatabase()` is unique to fake-indexeddb and is not part of the browser IndexedDB API. Use it only to reach the abnormal-close branch.
Supply structuredClone before auto registration patch-jsdom-clone
import structuredClone from 'core-js/stable/structured-clone.js';
globalThis.structuredClone ??= structuredClone;
await import('fake-indexeddb/auto');fake-indexeddb stopped bundling a `structuredClone` polyfill in version 5. Modern Node has the function, but some jsdom environments do not expose it.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| indexeddbshim | npm | Use it when an older environment needs IndexedDB behavior backed by WebSQL rather than an in-memory Node test double. |
| @happy-dom/global-registrator | npm | Use it when tests need a wider browser-like DOM environment and IndexedDB is only one of several missing globals. |
| jsdom | npm | Use it for DOM-focused Node tests, then add fake-indexeddb separately if those tests also touch IndexedDB. |
| idb | npm | Use it in application code when the native browser database exists and the problem is IndexedDB's callback-heavy API rather than test storage. |
More testing guides
pytest · chai · jsdom · vitest · playwright · coverage · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

