ブラウザストレージ全比較: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 を使用
  • 保存時の暗号化:機密データは JWTHash で処理してから保存
  • Same-Origin 分離:すべてのストレージは同一オリジンポリシーに従う

まとめ

ブラウザストレージは単一の localStorage から、キー・バリュー、構造化データ、HTTP キャッシュ、ファイルシステムをカバーする完全な体系へと進化しました。選定の核心はデータ特性へのマッチングです:単純設定 → localStorage、構造化データ → IndexedDB、HTTP キャッシュ → Cache API、高性能ファイル I/O → OPFS。

Cookie パーサー で Cookie 設定を確認、JWT ツール でトークン安全性を検証、Hash ツール で機密データをハッシュ化できます。

ブラウザローカルツールを無料で試す →

#localStorage#sessionStorage#IndexedDB#Cache API#存储对比