ブラウザストレージ全比較:localStorage、IndexedDB、Cache API、OPFS
技术架构(更新: 2026年6月8日)
5 つのブラウザストレージ機構の概要
モダンブラウザは 5 つの主要ストレージ機構を提供し、それぞれ異なる設計目標とユースケースを持っています:
| ストレージ | データ型 | 容量上限 | 永続性 | スレッドアクセス |
|---|---|---|---|---|
| localStorage | 文字列キー・バリュー | ~5-10 MB | 永続 | メインスレッドのみ |
| sessionStorage | 文字列キー・バリュー | ~5-10 MB | タブ閉じるまで | メインスレッドのみ |
| IndexedDB | 構造化データ + Blob | 数百 MB~無制限 | 永続 | メイン + Worker |
| Cache API | Request/Response ペア | IndexedDB と共有 | 永続 | メイン + Worker |
| OPFS | ファイルシステム | IndexedDB と共有 | 永続 | Worker のみ(同期) |
localStorage と sessionStorage
基本的な使い方
localStorage.setItem('theme', 'dark');
const theme = localStorage.getItem('theme');
localStorage.removeItem('theme');
localStorage.clear();
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
console.log(key, localStorage.getItem(key));
}
主な違い
| 特徴 | localStorage | sessionStorage |
|---|---|---|
| ライフタイム | 永続 | タブ閉じるまで |
| スコープ | 同一オリジン全タブで共有 | 現在のタブのみ |
| 典型的用途 | ユーザー設定、トークン | フォーム下書き、ページ状態 |
容量検出
function testLocalStorageQuota() {
const testKey = '__quota_test__';
let data = '';
try {
for (let i = 0; i < 1024; i++) data += 'a'.repeat(1024);
for (let mb = 1; mb < 20; mb++) {
localStorage.setItem(testKey, data.repeat(mb));
}
} catch (e) {
console.log('localStorage のクォータ超過');
} finally {
localStorage.removeItem(testKey);
}
}
注意点
- 同期ブロック:読み書きがメインスレッドをブロック、大量データは性能に影響
- 文字列のみ:オブジェクトは
JSON.stringify/JSON.parseが必要 - Storage イベント:同一オリジンの他タブで変更時に
storageイベントが発火
IndexedDB
基本的な使い方
const openRequest = indexedDB.open('myDatabase', 1);
openRequest.onupgradeneeded = (event) => {
const db = event.target.result;
const store = db.createObjectStore('users', { keyPath: 'id' });
store.createIndex('name', 'name', { unique: false });
};
openRequest.onsuccess = (event) => {
const db = event.target.result;
const tx = db.transaction('users', 'readwrite');
const store = tx.objectStore('users');
store.add({ id: 1, name: '田中', email: 'tanaka@example.com' });
store.get(1).onsuccess = (e) => {
console.log(e.target.result);
};
};
高度な機能
| 機能 | 説明 |
|---|---|
| トランザクション | 原子性を保証、読み書き分離 |
| インデックス | 非キーフィールドの効率的クエリ |
| カーソル | 大量データの逐次処理、一括読み込み回避 |
| Blob 保存 | File や Blob オブジェクトを直接保存 |
| Worker アクセス | Service Worker / Web Worker で利用可能 |
idb ライブラリで簡略化
import { openDB } from 'idb';
const db = await openDB('myDatabase', 1, {
upgrade(db) {
db.createObjectStore('users', { keyPath: 'id' });
}
});
await db.put('users', { id: 1, name: '田中' });
const user = await db.get('users', 1);
const allUsers = await db.getAll('users');
await db.delete('users', 1);
Cache API
基本的な使い方
const cache = await caches.open('v1');
await cache.put('/api/data', new Response(JSON.stringify({ foo: 'bar' })));
const response = await cache.match('/api/data');
const data = await response.json();
await cache.delete('/api/data');
Service Worker との連携
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cached) => {
if (cached) return cached;
return fetch(event.request).then((response) => {
const clone = response.clone();
caches.open('v1').then((cache) => {
cache.put(event.request, clone);
});
return response;
});
})
);
});
キャッシュ戦略の比較
| 戦略 | 説明 | ユースケース |
|---|---|---|
| Cache First | キャッシュ優先、ミス時にネットワーク | 静的アセット、フォント |
| Network First | ネットワーク優先、失敗時にキャッシュ | API データ、頻繁更新コンテンツ |
| Stale While Revalidate | キャッシュ返しつつバックグラウンド更新 | 非重要 API、画像 |
| Cache Only | キャッシュのみ | オフラインページ、プリキャッシュ |
| Network Only | ネットワークのみ | 非 GET リクエスト、リアルタイムデータ |
OPFS(Origin Private File System)
基本的な使い方
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('data.bin', { create: true });
const writable = await fileHandle.createWritable();
await writable.write(new Uint8Array([1, 2, 3, 4]));
await writable.close();
const file = await fileHandle.getFile();
const buffer = await file.arrayBuffer();
Worker での同期アクセス
// Worker 内で同期 OPFS を使用(極めて高速)
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('large.bin', { create: true });
const accessHandle = await fileHandle.createSyncAccessHandle();
const buffer = new ArrayBuffer(4);
accessHandle.write(buffer, { at: 0 });
accessHandle.flush();
accessHandle.close();
OPFS と File System Access API の比較
| 特徴 | OPFS | File System Access API |
|---|---|---|
| ユーザー許可 | 不要 | ユーザーがディレクトリを選択 |
| 可視性 | ブラウザ内部の仮想 FS | OS のリアルファイルシステム |
| Worker 同期 | 対応 | 非対応 |
| 永続性 | 永続 | ユーザー許可に依存 |
| ユースケース | 高性能一時ファイル処理 | ファイルエディター、エクスポート |
ストレージクォータと永続化
利用可能クォータの照会
const estimate = await navigator.storage.estimate();
console.log(`使用量: ${(estimate.usage / 1024 / 1024).toFixed(2)} MB`);
console.log(`クォータ: ${(estimate.quota / 1024 / 1024).toFixed(2)} MB`);
永続化の要求
const persisted = await navigator.storage.persist();
if (persisted) {
console.log('ストレージは永続化され、自動削除されません');
} else {
console.log('ストレージは圧迫時に削除される可能性があります');
}
ブラウザはストレージ圧迫時に非永続ストレージを自動削除する場合があります。
navigator.storage.persist()で永続化権限を要求できます。
選定ガイド
何を保存するか?
├── 単純キー・バリュー(< 5MB)
│ ├── タブ間共有が必要 → localStorage
│ └── 現在のタブのみ → sessionStorage
├── 構造化データ / 大量レコード
│ └── IndexedDB
├── HTTP リクエスト/レスポンスキャッシュ
│ └── Cache API
└── 大ファイル / バイナリ / 高性能 I/O
└── OPFS
実践的な例
| シナリオ | 推奨ストレージ | 理由 |
|---|---|---|
| ユーザーテーマ設定 | localStorage | 単純キー・バリュー、ページ間共有 |
| フォーム下書き | sessionStorage | 一時的、タブスコープ |
| オフラインツールデータ | IndexedDB | 構造化、インデックスクエリ対応 |
| 静的アセットキャッシュ | Cache API | Request/Response 向け設計 |
| 動画処理の一時ファイル | OPFS | Worker 同期 I/O、高性能 |
セキュリティ上の注意
- XSS リスク:localStorage は XSS で読み取り可能 — 機密トークンは保存しない
- HttpOnly Cookie:認証トークンは HttpOnly + Secure Cookie を使用
- 保存時の暗号化:機密データは JWT や Hash で処理してから保存
- Same-Origin 分離:すべてのストレージは同一オリジンポリシーに従う
まとめ
ブラウザストレージは単一の localStorage から、キー・バリュー、構造化データ、HTTP キャッシュ、ファイルシステムをカバーする完全な体系へと進化しました。選定の核心はデータ特性へのマッチングです:単純設定 → localStorage、構造化データ → IndexedDB、HTTP キャッシュ → Cache API、高性能ファイル I/O → OPFS。
Cookie パーサー で Cookie 設定を確認、JWT ツール でトークン安全性を検証、Hash ツール で機密データをハッシュ化できます。
ブラウザローカルツールを無料で試す →
#localStorage#sessionStorage#IndexedDB#Cache API#存储对比