の主な代替案は @capacitor-community/sqlite Capacitor 8 における @capgo/capacitor-fast-sqliOS、Android、Webに対応したネイティブSQLiteプラグインです。SQLCipherをオプションに保ち、Capacitor ブリッジではなくローカルHTTPチャネル経由でクエリデータを送信します。本ガイドでは両者を率直に比較し、コミュニティ版プラグインを使い続けるべきケースと、code とユーザーの既存データベースの両方を移行する手順を解説します。
なぜ代替案が求められているのか
@capacitor-community/sqlite は長年 Capacitor のデフォルトSQLiteプラグインとして利用されており、現在もメンテナンスされています(2026年8月に8.1.1をリリース)。移行する理由は具体的です:
- ブリッジのシリアライズ すべての結果がJSONとして Capacitor ブリッジを経由します。小規模なクエリなら問題ありませんが、同期や検索で数千行のデータをロードする際には顕著な影響が出ます。
- SQLCipherが常に含まれる 暗号化を使用しない場合でも、iOSとAndroidではSQLCipherに依存します。これによりネイティブサイズが増え、バイナリに暗号化 code が含まれるため、輸出コンプライアンスの回答で考慮する必要があります。
- Webのストレージモデル Web上では、
jeep-sqliteコンポーネントであるsql.jsをメモリ内で使用し、保存を呼び出したときにIndexedDBへ永続化します。saveToStore()保存を忘れないようにする必要があり、データベース全体がメモリ上に存在します。 - API のサーフェスが大きい 接続ラッパー、整合性チェック、読み取り専用や非準拠接続、同期テーブル、JSONのインポート/エクスポート。強力ですが、「SQLを実行する」だけにしては学習コストが高すぎます。
- アプリごとに1つのパスフレーズ。 暗号化には、プラグインに保存された単一のシークレットを使用します(
setEncryptionSecret)、これはアプリ内のすべての暗号化データベースで共有されます)。
比較表
@capacitor-community/sqlite 8.1 |
@capgo/capacitor-fast-sql 8.2 |
|
|---|---|---|
| プラットフォーム | iOS, Android, Web, Electron | iOS, Android, Web |
| データパス | Capacitor ブリッジ | 接続ごとのトークンを使用するローカルHTTPサーバー (Native) |
| Webエンジン | jeep-sqlite (sql.js + IndexedDB, 手動) saveToStore) |
公式 @sqlite.org/sqlite-wasm OPFSを使用し、ファイルへ直接書き込み |
| 暗号化 | SQLCipherを常に同梱、プラグインでパスフレーズを管理 | SQLCipherはオプション、データベースごとにキーを渡す connect() |
| Swift Package Manager | はい (Package.swift) |
はい (Package.swift) |
| スキーマのバージョン管理 | upgradeStatements / addUpgradeStatement |
通常は独自に管理 PRAGMA user_version |
| JSONのインポート/エクスポート、テーブル同期 | はい | いいえ |
| アセットからの事前作成済みDB | copyFromAssets() |
事前にファイルを自身でコピー connect() |
| Key-valueヘルパー | いいえ | KeyValueStore |
| BLOB | はい | はい、あります Uint8Array |
| ORMサポート | TypeORM標準搭載 capacitor ドライバー |
カスタムドライバー(Kyselyも動作良好) |
| 追加のネイティブ設定 | Web: コピー sql-wasm.wasm |
iOSと NSAllowsLocalNetworking、Android localhostのcleartextルール |
| メンテナー | Capacitor コミュニティ | Capgo |
コミュニティプラグインを使い続けるべきケース
実用性を重視。以下に該当するなら:
- 以下をリリースしている: Electron ビルド、
- 以下を使用している: TypeORM (その capacitor ドライバーはコミュニティプラグイン向けに書かれています。詳細は TypeORM と Capacitor を参照)),
- 以下に依存している: JSONのインポート/エクスポート、またはテーブルの同期 それらを再ビルドしたくない場合、
- クエリが小さく、アプリが現在問題なく動作しているなら、
Fast SQLが適しているケース
移行すべきケース:
- 大規模なデータセットを読み書きする場合(同期エンジン、オフラインカタログ、検索インデックス、CRDTログなど)、
- KeychainやKeystoreのキーを使って、一部のデータベースだけを暗号化したい、
- SQLCipherを必要としないアプリに、わざわざ組み込みたくない、
- インメモリのコピーではなく、OPFS経由でWeb上でも本物のSQLiteファイルを使いたい、
- 接続・クエリ・実行・トランザクションだけのシンプルな API が欲しい。
Fast SQL自体の詳しい使い方は、こちらをご覧ください: Capacitor アプリでSQLiteを使う方法.
ステップ1:旧プラグインと併用してFast SQLをインストール
既存データを移行できるよう、コミュニティプラグインは1リリースの間はインストールしたままにしてください。
bun add @capgo/capacitor-fast-sql
bunx cap sync
Fast SQLに必要なネイティブ設定:
- iOSと:
NSAppTransportSecurity>NSAllowsLocalNetworking=trueにおけるInfo.plist. - Androidでは:
network_security_config.xmlクリアテキストを許可するlocalhostと127.0.0.1、マニフェストから参照されています。 - 暗号化:
net.zetetic:sqlcipher-androidAndroidアプリモジュールおよびCapgoCapacitorFastSql/SQLCipheriOSでのpod。詳細は CapacitorでのSQLite暗号化. - Web:
Cross-Origin-Opener-Policy: same-originとCross-Origin-Embedder-Policy: require-corpOPFS用のヘッダー。
ステップ 2: API をマッピングする
データベースを開く
変更前:
import { CapacitorSQLite, SQLiteConnection } from '@capacitor-community/sqlite';
const sqlite = new SQLiteConnection(CapacitorSQLite);
const db = await sqlite.createConnection('app', false, 'no-encryption', 1, false);
await db.open();
変更後:
import { FastSQL } from '@capgo/capacitor-fast-sql';
const db = await FastSQL.connect({ database: 'app', walMode: true, performancePresets: true });
FastSQL.connect() データベースが既に開いている場合は既存の接続を返すため、余計な isConnection / retrieveConnection 処理は不要です。
メソッドのマッピング
| コミュニティプラグイン | 高速なSQL |
|---|---|
createConnection() + open() |
FastSQL.connect({ database }) |
closeConnection(name) |
FastSQL.disconnect(name) |
db.query(sql, values) を返します { values } |
db.query(sql, params) 行を返します |
db.run(sql, values) を返します { changes: { changes, lastId } } |
db.run(sql, params) を返します { rowsAffected, insertId } |
db.execute(multiStatementString) |
1つ db.execute(sql) ステートメントごと、または db.executeBatch([...]) |
db.executeSet(set) |
db.executeBatch(ops) を使用して { statement, params } |
beginTransaction / commitTransaction / rollbackTransaction |
db.transaction(async (tx) => ...) または beginTransaction() / commit() / rollback() |
addUpgradeStatement / upgradeStatements |
ある PRAGMA user_version マイグレーションランナー |
copyFromAssets() |
バンドルをコピー .db 次のように分類しています Directory.Data 最初の connect() |
setEncryptionSecret() + mode: 'secret' |
encrypted: true, encryptionKey で connect() |
initWebStore() / saveToStore() |
不要です。OPFSは書き込みを保持します |
クエリと書き込み
変更前:
const res = await db.query('SELECT * FROM notes WHERE pinned = ?', [1]);
const notes = res.values ?? [];
const { changes } = await db.run('INSERT INTO notes (title) VALUES (?)', ['Hello']);
const id = changes?.lastId;
変更後:
const notes = await db.query('SELECT * FROM notes WHERE pinned = ?', [1]);
const { insertId } = await db.run('INSERT INTO notes (title) VALUES (?)', ['Hello']);
どちらのプラグインも、カラム名をキーとしたオブジェクトとして行を返します。
マルチステートメントの実行
コミュニティ版の execute() 複数のステートメントを以下で区切った文字列を受け入れます ;. Fast SQLは呼び出しごとに1つのステートメントを準備します。SQLを分割するか、より良い方法として、ステートメントを配列として保持してください:
const schema = [
'CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL)',
'CREATE INDEX IF NOT EXISTS idx_notes_title ON notes (title)',
];
await db.executeBatch(schema.map((statement) => ({ statement })));
以下で分割しないでください: ; 単純な方法で: split(';') ステートメント内にトリガーの本体や、セミコロンを含む文字列リテラルが含まれている場合。
ステートメントを user_version にアップグレード
コミュニティプラグインはスキーマバージョンを PRAGMA user_version にも保存しています。バージョン番号を維持すれば、ステップ3のファイル移行後、既存ユーザーのデータベースはすでに正しいバージョンになっています。
import type { SQLConnection } from '@capgo/capacitor-fast-sql';
// Same content as your old upgrade statements, index 0 = version 1
const versions: string[][] = [
['CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL)'],
['ALTER TABLE notes ADD COLUMN pinned INTEGER NOT NULL DEFAULT 0'],
];
export async function migrate(db: SQLConnection) {
const [{ user_version }] = await db.query('PRAGMA user_version');
for (let v = Number(user_version); v < versions.length; v++) {
await db.transaction(async (tx) => {
for (const statement of versions[v]) await tx.execute(statement);
await tx.execute(`PRAGMA user_version = ${v + 1}`);
});
}
}
実際の user_version を既存のインストール環境で確認してから、これを前提にしてください。確信が持てない場合は、現在のリリースで旧プラグインからログを出力してください。
初期データ入りデータベース
コミュニティプラグインの copyFromAssets() は、初回起動時に同梱データベースをコピーします。Fast SQLでは、接続前にプラグインが参照する場所にファイルを置いてください。Fast SQLは、 <name>.db における Documents をiOSでは、Androidではアプリの files ディレクトリに保存します。どちらも Directory.Data における @capacitor/filesystem:
import { Directory, Filesystem } from '@capacitor/filesystem';
import { FastSQL } from '@capgo/capacitor-fast-sql';
async function openCatalog() {
const exists = await Filesystem.stat({ path: 'catalog.db', directory: Directory.Data })
.then(() => true)
.catch(() => false);
if (!exists) {
const blob = await (await fetch('/assets/catalog.db')).blob();
const base64 = await new Promise<string>((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve((reader.result as string).split(',')[1]);
reader.readAsDataURL(blob);
});
await Filesystem.writeFile({ path: 'catalog.db', data: base64, directory: Directory.Data });
}
return FastSQL.connect({ database: 'catalog', readOnly: true });
}
大きなファイルは、チャンク単位でダウンロードするか、圧縮ファイルを同梱して、JavaScriptのbase64ではなくファイルプラグインのネイティブコピーを使ってください。
ステップ 3: 既存のユーザーデータを移行する
アプリをアップデートしたユーザーのデバイスには、コミュニティプラグインによって作成されたデータベースが存在します。これは、別の名前で異なるパスに保存されています:
| コミュニティプラグイン | 高速なSQL | |
|---|---|---|
| iOSと | Documents/<name>SQLite.db (デフォルト iosDatabaseLocation) |
Documents/<name>.db |
| Androidでは | databases/<name>SQLite.db |
files/<name>.db |
オプション A: ファイルをコピー(暗号化されていないデータベース)
最速かつ、インデックスやトリガーなど user_version.
import { CapacitorSQLite, SQLiteConnection } from '@capacitor-community/sqlite';
import { Directory, Filesystem } from '@capacitor/filesystem';
import { Preferences } from '@capacitor/preferences';
export async function moveCommunityDatabase(name: string): Promise<void> {
const done = await Preferences.get({ key: `sqlite-moved:${name}` });
if (done.value === '1') return;
const sqlite = new SQLiteConnection(CapacitorSQLite);
const exists = (await sqlite.isDatabase(name)).result;
if (exists) {
const conn = await sqlite.createConnection(name, false, 'no-encryption', 1, false);
await conn.open();
await conn.execute('PRAGMA wal_checkpoint(TRUNCATE)', false).catch(() => undefined);
const { url } = await conn.getUrl();
await sqlite.closeConnection(name, false);
if (url) {
await Filesystem.copy({ from: url, to: `${name}.db`, toDirectory: Directory.Data });
}
}
await Preferences.set({ key: `sqlite-moved:${name}`, value: '1' });
}
最初に呼び出してください FastSQL.connect({ database: name }). 注意事項:
getUrl()(iOSおよびAndroid) でデータベースファイルのURLを返します。完全なfile://URLをdirectory渡すことで、Filesystemプラグインがサンドボックス内の任意のパスから読み込めるようになります。- 接続を閉じ、事前にチェックポイントを作成することで、最新の書き込みが残らないようにします。
-walファイル。 - 古いファイルは1リリース分保持し、移行が完了したことを確認してから、communityの
delete()メソッドで削除してください。その後、communityプラグインを削除します。
オプションB: JavaScriptで行をコピーする(暗号化データベースやスキーマ変更の場合)
ソースがコミュニティプラグインの保存されたシークレットで暗号化されている場合、最もシンプルで安全な方法は、そのプラグインに復号させ、新しいFast SQLデータベースにデータをコピーすることです。これにより、セキュアストレージから取得したデータベースごとの新しいキーで暗号化することも可能になります。
import { CapacitorSQLite, SQLiteConnection } from '@capacitor-community/sqlite';
import { FastSQL } from '@capgo/capacitor-fast-sql';
import { Preferences } from '@capacitor/preferences';
export async function copyRows(name: string, target: { encryptionKey?: string }) {
// Record which destination mode was migrated, so a later call with a different target fails loudly
const mode = target.encryptionKey ? 'encrypted' : 'plain';
const done = await Preferences.get({ key: `sqlite-copied:${name}` });
if (done.value === mode) return;
if (done.value) throw new Error(`${name} was already copied as ${done.value}, not ${mode}`);
const sqlite = new SQLiteConnection(CapacitorSQLite);
const src = await sqlite.createConnection(name, true, 'secret', 1, false);
await src.open();
try {
const dst = await FastSQL.connect({
database: name,
encrypted: Boolean(target.encryptionKey),
encryptionKey: target.encryptionKey,
});
const objects = ((await src.query(
`SELECT type, name, sql FROM sqlite_master
WHERE sql IS NOT NULL AND name NOT LIKE 'sqlite_%'`,
)).values ?? []) as { type: string; name: string; sql: string }[];
const tables = objects.filter((o) => o.type === 'table');
const others = objects.filter((o) => o.type !== 'table');
const version = (await src.query('PRAGMA user_version')).values?.[0]?.user_version ?? 0;
await dst.transaction(async (tx) => {
for (const t of tables) await tx.execute(t.sql);
for (const t of tables) {
const rows = (await src.query(`SELECT * FROM "${t.name}"`)).values ?? [];
if (!rows.length) continue;
const cols = Object.keys(rows[0]);
const statement = `INSERT INTO "${t.name}" (${cols.map((c) => `"${c}"`).join(', ')}) VALUES (${cols.map(() => '?').join(', ')})`;
await tx.executeBatch(rows.map((r) => ({ statement, params: cols.map((c) => r[c]) })));
}
for (const o of others) await tx.execute(o.sql);
await tx.execute(`PRAGMA user_version = ${Number(version)}`);
});
// Only mark the copy as done once the transaction has committed
await Preferences.set({ key: `sqlite-copied:${name}`, value: mode });
} finally {
await sqlite.closeConnection(name, false);
}
}
使用する 'no-encryption' と false における createConnection ソースが暗号化されていない場合。コミュニティプラグインには iosIsEncryption / androidIsEncryption における capacitor.config 暗号化モードについては、使っていればすでに利用できます。大きなテーブルは、次を使ってページングしてください。 WHERE rowid > ? ORDER BY rowid LIMIT 5000.
どちらのプラグインも SQLCipher 4 のデフォルトを使っているため、暗号化されたファイルは同じパスフレーズで Fast SQL から直接開けることもあります。ただし、コミュニティプラグインはそのパスフレーズを内部で管理しているので、行コピーならその詳細に依存せずに済みます。
ステップ 4: 古いプラグインを削除する
移行を入れたリリースを1〜2回出した後:
bun remove @capacitor-community/sqlite jeep-sqlite
bunx cap sync
削除 sql-wasm.wasm アセットおよび任意の jeep-sqlite でのセットアップ main.ts。プラグインを削除すると SQLCipher への依存もなくなるため、Fast SQL の暗号化を有効にしない場合は、iOS と Android のバイナリが小さくなります。
データ移行 code は JavaScript なので、次と一緒に配信できます: Capgo Live Updates、ただし Fast SQL を追加するリリースはネイティブの変更を伴うため、ストアビルドが必要です。先にネイティブビルドを配信してください。 Capgo のビルド Macを所有していない場合でも、クラウド上で生成可能です(2026年4月以降、App StoreへのアップロードにはXcode 26以降が必要になります)。
トラブルシューティング
Fast SQLは接続は速いものの、iOSではすべてのクエリが失敗します。 NSAllowsLocalNetworking アプリの Info.plist、または追加後にアプリを再ビルドしていません。
Android: CLEARTEXT communication to localhost not permitted. localhost を domain-config ネットワークセキュリティ設定に追加してください。SSLピンニング用の設定が既にある場合は、それと統合してください。
スキーマの一部しか作成されませんでした。 複数のステートメントを含む文字列が execute()に渡されました。配列に分割してください。
INSERT ... RETURNING Android では何も返されません。 Fast SQL 8.2 では、Android は以下の文字列で始まるステートメントに対してのみ行を返します: SELECT, PRAGMA または EXPLAIN. 入力が不正な場合は、 insertId と run().
Android での読み取り時、Boolean の値が一致しません。 渡す 1/0 の代わりに true/false クエリパラメータ内において。Androidは読み取り用クエリパラメータをテキストとしてバインドします。
コピーされたデータベースは空です。 コミュニティプラグインはカスタムの iosDatabaseLocation、またはソース名が異なります。返されたURLをログに出力してください。 getUrl().
旧プラグインのWebデータは失われます。 コミュニティ版プラグインはIndexedDBにWebデータを保存していましたが、 jeep-sqliteFast SQLはOPFSを使用します。バックエンドからWebクライアントを再同期するか、旧プラグインで exportToJson エクスポートして、Fast SQLにレコードをインポートしてください。
その他のオプション
@capgo/capacitor-data-storage-sqlite本当に必要なのがSQLiteベースの文字列キー・バリューストアなら、以下を参照してください。 Capacitorにおけるキー・バリュー・ストレージ.- 上位レイヤーでのORMまたはクエリビルダー: Kysely は、小さなカスタムドライバを介してFast SQLと連携できます。 Drizzle は、現時点ではコミュニティ版プラグインとの相性がより良いです。
高速なSQL API の全容は プラグインのドキュメント および プラグインのページ.