dexie vs idb vs localforage
Web アプリにおけるクライアント側データベースライブラリの比較
dexieidblocalforage類似パッケージ:

Web アプリにおけるクライアント側データベースライブラリの比較

dexieidblocalforage はすべて、ブラウザ内のデータ保存を簡単にするためのライブラリです。localforage は localStorage のような単純なキーバリュー形式を提供し、バックエンドで IndexedDB や WebSQL を自動的に選択します。一方、dexieidb は IndexedDB に特化しており、より高度なクエリやトランザクション管理をサポートします。dexie はスキーマ管理やクエリビルダーを備えた高機能なラッパーであり、idb は IndexedDB のネイティブ API を Promise ベースに簡略化した軽量なラッパーです。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
dexie014,2833.23 MB5881ヶ月前Apache-2.0
idb07,32382.8 kB571年前ISC
localforage025,777-2495年前Apache-2.0

Dexie vs idb vs localforage: 構造、クエリ、管理の比較

ブラウザ内でデータを保存する際、dexieidblocalforage は代表的な選択肢ですが、それぞれ設計思想と得意とする領域が異なります。これらはすべて非同期処理をサポートしますが、データの扱い方や管理機能に大きな違いがあります。実務でどのライブラリを選ぶべきか、技術的な観点から深く比較します。

🗄️ データモデルと保存形式

localforage は localStorage と同じキーバリュー形式を採用しています。

  • データは名前付きのキーで保存され、複雑なクエリはできません。
  • 内部で IndexedDB を使いますが、その機能は隠蔽されます。
// localforage: 単純なキーバリュー保存
await localforage.setItem('user', { id: 1, name: 'Alice' });
const user = await localforage.getItem('user');

idb は IndexedDB のオブジェクトストアを直接使用します。

  • キーバリューですが、インデックスを張って検索可能です。
  • ネイティブの構造に近い形でデータを扱います。
// idb: オブジェクトストアへの保存
const db = await openDB('my-db', 1, {
  upgrade(db) {
    db.createObjectStore('users', { keyPath: 'id' });
  },
});
await db.put('users', { id: 1, name: 'Alice' });
const user = await db.get('users', 1);

dexie はテーブルとスキーマを定義できる ORM 風のアプローチを取ります。

  • データをテーブルとして定義し、フィールドにインデックスを設定できます。
  • より直感的なデータモデルを構築できます。
// dexie: テーブル定義と保存
const db = new Dexie('my-db');
db.version(1).stores({ users: 'id, name' });
await db.users.put({ id: 1, name: 'Alice' });
const user = await db.users.get(1);

🔍 データ検索とクエリ機能

localforage はキーによる取得のみをサポートします。

  • 特定の条件でデータをフィルタリングする機能はありません。
  • 全データ取得後に JavaScript でフィルタする必要があり、大量データでは非効率です。
// localforage: キー指定のみ可能
const value = await localforage.getItem('specific-key');
// 条件検索は不可(全取得してフィルタする必要がある)

idb は IndexedDB のインデックス機能を利用できます。

  • getAllFromIndex などで効率的に検索できます。
  • 範囲検索や一意性の制約も利用可能です。
// idb: インデックスを利用した検索
const db = await openDB('my-db');
// 'name' インデックスを使って検索
const users = await db.getAllFromIndex('users', 'name', 'Alice');

dexie は強力なクエリビルダーを提供します。

  • whereequalsabove などのメソッドで複雑な検索を記述できます。
  • コードが読みやすく、メンテナンス性が高いです。
// dexie: クエリビルダーによる検索
const users = await db.users.where('name').equals('Alice').toArray();
const adults = await db.users.where('age').above(18).toArray();

🔄 スキーマ管理とバージョンアップ

localforage はスキーマ管理機能を持ちません。

  • データ構造の変更はアプリケーション側で手動で処理する必要があります。
  • 大規模なデータ移行が必要な場合、負担が大きくなります。
// localforage: 手動でデータ構造を管理
const data = await localforage.getItem('user');
data.newField = 'value'; // 構造変更は自己責任
await localforage.setItem('user', data);

idbupgrade コールバックでスキーマ変更を処理します。

  • データベースバージョンを指定し、変更が必要な場合のみコードが実行されます。
  • 柔軟ですが、移行ロジックは自分で書く必要があります。
// idb: upgrade コールバックで管理
const db = await openDB('my-db', 2, {
  upgrade(db, oldVersion, newVersion, transaction) {
    if (oldVersion < 2) {
      const store = transaction.objectStore('users');
      store.createIndex('email', 'email');
    }
  },
});

dexie はバージョンチェーンによる明確なマイグレーション管理を提供します。

  • 各バージョンで必要なスキーマ定義を記述します。
  • 過去のバージョンからのアップグレードパスを自動的に構築します。
// dexie: バージョンチェーンで管理
db.version(1).stores({ users: 'id' });
db.version(2).stores({ users: 'id, email' }); // email インデックス追加
db.version(3).upgrade(tx => {
  return tx.table('users').toCollection().modify(u => { u.role = 'user'; });
});

🔒 トランザクションと整合性

localforage はトランザクションを明示的に管理しません。

  • 個別の操作は原子性を持ちますが、複数の操作をまとめる機能は限定的です。
  • 複雑なデータ整合性が必要な場合には不向きです。
// localforage: 単一操作は安全だが、複数操作の保証は弱い
await localforage.setItem('a', 1);
await localforage.setItem('b', 2); // 中間で失敗すると整合性が崩れる可能性

idb はネイティブのトランザクション機能をラップしています。

  • transaction メソッドで複数の操作をまとめることができます。
  • 失敗時にロールバックする機能を利用できます。
// idb: 明示的なトランザクション管理
const tx = db.transaction('users', 'readwrite');
await tx.objectStore('users').put({ id: 1 });
await tx.objectStore('logs').add({ action: 'update' });
await tx.done; // 完了を待機

dexie は操作を自動的にトランザクションでラップします。

  • 複数のテーブルにまたがる操作も自動的に処理されます。
  • 開発者がトランザクションを意識せずに安全なコードを書けます。
// dexie: 自動トランザクション管理
await db.transaction('rw', db.users, db.logs, async () => {
  await db.users.put({ id: 1 });
  await db.logs.add({ action: 'update' });
});

📊 比較サマリー

機能localforageidbdexie
データモデルキーバリューオブジェクトストアテーブル/スキーマ
クエリ機能キー取得のみインデックス検索豊富なクエリビルダー
マイグレーション手動upgrade コールバックバージョンチェーン
トランザクション限定的明示的管理自動管理
学習コスト
推奨用途単純キャッシュ軽量なデータベース複雑なアプリケーション

💡 結論と推奨事項

localforage は、単純なキーバリュー保存が必要な場合や、localStorage の非同期版として使いたい場合に適しています — ただし、新しい複雑なアプリでは推奨されません。IndexedDB の真の力を引き出せないため、データが増えると性能や管理面で課題が出ます。

idb は、IndexedDB の機能をそのまま使いたい開発者に最適です — 軽量で、ブラウザ標準に忠実でありながら、Promise ベースで扱いやすくなっています。余計な抽象化を好まないチームや、バンドルサイズを極限まで減らしたい場合に選択すべきです。

dexie は、本格的なクライアント側データベースが必要な場合に最適です — スキーマ管理、クエリ機能、トランザクション処理が充実しており、大規模なアプリケーション開発を支えます。データの整合性や将来の拡張性を重視するプロジェクトでは、このライブラリが最も堅牢な選択肢となります。

最終的には、プロジェクトの複雑さとチームの要件に合わせて選択してください — 単純な保存なら localforage、制御と軽量化なら idb、機能と生産性なら dexie が適しています。

選び方: dexie vs idb vs localforage

  • dexie:

    複雑なデータ構造や頻繁なスキーマ変更が必要なプロジェクトには dexie を選択してください。バージョン管理機能により、データベースのアップグレードを安全に処理できます。また、高度なクエリ機能が必要な場合や、コードの可読性を重視するチームに適しています。

  • idb:

    IndexedDB の機能を直接使用したいが、ネイティブの複雑な API は避けたい場合に idb を選択してください。軽量で依存関係が少なく、ブラウザの標準機能に忠実な実装が必要です。シンプルな保存機能だけでなく、インデックス検索も必要だが、オーバーヘッドは最小限に抑えたい場合に最適です。

  • localforage:

    単純なキーバリュー保存のみが必要で、IndexedDB の詳細を抽象化したい場合に localforage を選択してください。localStorage の非同期版として使いたい場合や、レガシーブラウザへのフォールバックが必要な古いプロジェクトの維持に適しています。ただし、新しい複雑なアプリでは他の選択肢を検討すべきです。

dexie のREADME

Dexie.js

NPM Version Build Status Join our Discord

Dexie.js is a wrapper library for indexedDB - the standard database in the browser. https://dexie.org.

Why Dexie.js?

IndexedDB is the portable database for all browser engines. Dexie.js makes it fun and easy to work with.

But also:

  • Dexie.js is widely used by 100,000 of web sites, apps and other projects and supports all browsers, Electron for Desktop apps, Capacitor for iOS / Android apps and of course pure PWAs.
  • Dexie.js works around bugs in the IndexedDB implementations, giving a more stable user experience.
  • Need sync? Dexie Cloud adds real-time sync, auth, and collaboration on top of Dexie.js — no backend needed.

Hello World (vanilla JS)

<!DOCTYPE html>
<html>
  <head>
    <script type="module">
      // Import Dexie
      import { Dexie } from 'https://unpkg.com/dexie/dist/modern/dexie.mjs';

      //
      // Declare Database
      //
      const db = new Dexie('FriendDatabase');
      db.version(1).stores({
        friends: '++id, age'
      });

      //
      // Play with it
      //
      try {
        await db.friends.add({ name: 'Alice', age: 21 });

        const youngFriends = await db.friends
            .where('age')
            .below(30)
            .toArray();

        alert(`My young friends: ${JSON.stringify(youngFriends)}`);
      } catch (e) {
        alert(`Oops: ${e}`);
      }
    </script>
  </head>
</html>

Yes, it's that simple. Read the docs to get into the details.

Hello World (legacy script tags)

<!DOCTYPE html>
<html>
  <head>
    <script src="https://unpkg.com/dexie/dist/dexie.js"></script>
    <script>

      //
      // Declare Database
      //
      const db = new Dexie('FriendDatabase');
      db.version(1).stores({
        friends: '++id, age'
      });

      //
      // Play with it
      //
      db.friends.add({ name: 'Alice', age: 21 }).then(() => {
        return db.friends
          .where('age')
          .below(30)
          .toArray();
      }).then(youngFriends => {
        alert (`My young friends: ${JSON.stringify(youngFriends)}`);
      }).catch (e => {
        alert(`Oops: ${e}`);
      });

    </script>
  </head>
</html>

Hello World (React + Typescript)

Real-world apps are often built using components in various frameworks. Here's a version of Hello World written for React and Typescript. There are also links below this sample to more tutorials for different frameworks...

import React from 'react';
import { Dexie, type EntityTable } from 'dexie';
import { useLiveQuery } from 'dexie-react-hooks';

// Typing for your entities (hint is to move this to its own module)
export interface Friend {
  id: number;
  name: string;
  age: number;
}

// Database declaration (move this to its own module also)
export const db = new Dexie('FriendDatabase') as Dexie & {
  friends: EntityTable<Friend, 'id'>;
};
db.version(1).stores({
  friends: '++id, age',
});

// Component:
export function MyDexieReactComponent() {
  const youngFriends = useLiveQuery(() =>
    db.friends
      .where('age')
      .below(30)
      .toArray()
  );

  return (
    <>
      <h3>My young friends</h3>
      <ul>
        {youngFriends?.map((f) => (
          <li key={f.id}>
            Name: {f.name}, Age: {f.age}
          </li>
        ))}
      </ul>
      <button
        onClick={() => {
          db.friends.add({ name: 'Alice', age: 21 });
        }}
      >
        Add another friend
      </button>
    </>
  );
}

Tutorials for React, Svelte, Vue, Angular and vanilla JS

API Reference

Samples

Performance

Dexie has kick-ass performance. Its bulk methods take advantage of a lesser-known feature in IndexedDB that makes it possible to store stuff without listening to every onsuccess event. This speeds up the performance to a maximum.

Supported operations

above(key): Collection;
aboveOrEqual(key): Collection;
add(item, key?): Promise;
and(filter: (x) => boolean): Collection;
anyOf(keys[]): Collection;
anyOfIgnoreCase(keys: string[]): Collection;
below(key): Collection;
belowOrEqual(key): Collection;
between(lower, upper, includeLower?, includeUpper?): Collection;
bulkAdd(items: Array): Promise;
bulkDelete(keys: Array): Promise;
bulkPut(items: Array): Promise;
clear(): Promise;
count(): Promise;
delete(key): Promise;
distinct(): Collection;
each(callback: (obj) => any): Promise;
eachKey(callback: (key) => any): Promise;
eachPrimaryKey(callback: (key) => any): Promise;
eachUniqueKey(callback: (key) => any): Promise;
equals(key): Collection;
equalsIgnoreCase(key): Collection;
filter(fn: (obj) => boolean): Collection;
first(): Promise;
get(key): Promise;
inAnyRange(ranges): Collection;
keys(): Promise;
last(): Promise;
limit(n: number): Collection;
modify(changeCallback: (obj: T, ctx:{value: T}) => void): Promise;
modify(changes: { [keyPath: string]: any } ): Promise;
noneOf(keys: Array): Collection;
notEqual(key): Collection;
offset(n: number): Collection;
or(indexOrPrimayKey: string): WhereClause;
orderBy(index: string): Collection;
primaryKeys(): Promise;
put(item: T, key?: Key): Promise;
reverse(): Collection;
sortBy(keyPath: string): Promise;
startsWith(key: string): Collection;
startsWithAnyOf(prefixes: string[]): Collection;
startsWithAnyOfIgnoreCase(prefixes: string[]): Collection;
startsWithIgnoreCase(key: string): Collection;
toArray(): Promise;
toCollection(): Collection;
uniqueKeys(): Promise;
until(filter: (value) => boolean, includeStopEntry?: boolean): Collection;
update(key: Key, changes: { [keyPath: string]: any }): Promise;

This is a mix of methods from WhereClause, Table and Collection. Dive into the API reference to see the details.

Dexie Cloud

Dexie Cloud is the easiest way to add sync, authentication, and real-time collaboration to your Dexie app. You keep writing frontend code with Dexie.js — Dexie Cloud handles the rest.

What you get:

  • 🔄 Sync across devices — changes propagate in real time, no polling needed
  • 🔐 Authentication — built-in user auth, no identity provider required
  • 🛡️ Access control — share data between users with fine-grained permissions
  • 📁 File & blob storage — store attachments alongside your structured data
  • ✈️ Offline-first — works fully offline, syncs when back online

Getting started is just a few lines:

npm install dexie-cloud-addon
import Dexie from 'dexie';
import dexieCloud from 'dexie-cloud-addon';

const db = new Dexie('MyDatabase', { addons: [dexieCloud] });
db.version(1).stores({ items: '@id, title' });
db.cloud.configure({ databaseUrl: 'https://<your-db>.dexie.cloud' });

That's it. Your existing Dexie app now syncs. Hosted cloud or self-hosted on your own infrastructure. 👋

Quickstart guide

Sample app:

Source: Dexie Cloud To-do app

Live demo: https://dexie.github.io/Dexie.js/dexie-cloud-todo-app/

Samples

https://dexie.org/docs/Samples

https://github.com/dexie/Dexie.js/tree/master/samples

Knowledge Base

https://dexie.org/docs/Questions-and-Answers

Website

https://dexie.org

Install via npm

npm install dexie

Download

For those who don't like package managers, here's the download links:

UMD (for legacy script includes as well as commonjs require):

https://unpkg.com/dexie@latest/dist/dexie.min.js

https://unpkg.com/dexie@latest/dist/dexie.min.js.map

Modern (ES module):

https://unpkg.com/dexie@latest/dist/modern/dexie.min.mjs

https://unpkg.com/dexie@latest/dist/modern/dexie.min.mjs.map

Typings:

https://unpkg.com/dexie@latest/dist/dexie.d.ts

Contributing

See CONTRIBUTING.md

Build

pnpm install
pnpm run build

Test

pnpm test

Watch

pnpm run watch

Browser testing via
TestMu AI (Formerly LambdaTest)