ブラウザにデータを保存する 3 つの方法、それぞれが違う
ウェブ開発者は誰もが最終的に同じ質問にぶつかります。ページをリフレッシュしてもデータを残すにはどこに保存すればいい? ブラウザは 3 つの主要な選択肢を提供しており、間違えると追跡が面倒なバグにつながります。
localStorage、sessionStorage、Cookie はすべてブラウザにデータを保存しますが、寿命、容量、サーバーへの送信の有否という点で挙動が異なります。これらの違いを理解することで、古典的なミスを避けられます。ユーザー設定を Cookie に入れて 1 ヶ月後に消えたことに気づいたり、大きな JSON を Cookie に入れてリクエストサイズが膨らんだりするといったことです。
localStorage は手動で消すまで残る
localStorage はブラウザセッションをまたいで永続化されるキーバリューストアです。タブを閉じ、ブラウザを閉じ、パソコンを再起動しても、戻ってきたときデータはまだあります。オリジンごとのストレージ上限は通常 5〜10 MB 程度で、設定、履歴、小さなデータセットには十分です。
// 値を保存
localStorage.setItem("theme", "dark");
// 読み取り
const theme = localStorage.getItem("theme");
// 削除
localStorage.removeItem("theme");
// このオリジンのすべてをクリア
localStorage.clear();
API は同期的でシンプルです。文字列を保存し、文字列が返ってきます。オブジェクトを保存する必要がある場合は、JSON.stringify() でシリアライズし、JSON.parse() で戻します。
const history = [
{ url: "https://example.com/stream.m3u8", date: "2026-06-23" },
{ url: "https://example.com/live.m3u8", date: "2026-06-22" },
];
localStorage.setItem("playbackHistory", JSON.stringify(history));
Anoiona Tools では、M3U8 プレーヤーの再生履歴、テーマ設定、言語選択に localStorage を使っています。訪問のたびに残すべきものですが、デバイス間で同期する必要はありません。
注意点が一つあります。localStorage は同期的でブロッキングです。大量のデータを書き込むと、メインスレッドが一時停止します。ほとんどのユースケースでは気になりませんが、数 MB を保存すると目に見えるカクつきが発生する可能性があります。
sessionStorage はタブを閉じると消える
sessionStorage は localStorage と似た動作をしますが、重要な違いが一つあります。カレントタブにスコープされ、タブを閉じるとクリアされます。同じサイトを 2 つのタブで開くと、それぞれのタブが独立した sessionStorage を持ちます。
sessionStorage.setItem("currentStep", "3");
// ページをリフレッシュしても値は残る
// タブを閉じると値は消える
これにより、sessionStorage はマルチステップフォーム、ウィザードフロー、永続化すべきでない一時的な状態に適しています。ユーザーがフォームの入力を始めて、誤ってタブを閉じ、戻ってきた場合、困惑する半分入力された状態ではなく、新しい状態から始められます。
sessionStorage のストレージ上限と API は localStorage と同じです。違いは寿命とタブごとの隔離性だけです。
ほとんどの開発者はデフォルトで localStorage を選び、sessionStorage の存在を忘れがちです。データが本当にタブのクロス後も残る必要があるかどうか、考えてみる価値があります。必要なければ、sessionStorage はよりクリーンな選択です。時間が経っても蓄積されないからです。
Cookie はサーバーのためのもの
Cookie は localStorage や sessionStorage と根本的に異なります。サーバーへのすべての HTTP リクエストで自動的に送信されるからです。これが Cookie の主な目的です。クライアントに関する情報をサーバーに伝えることです。
// 7 日間有効な Cookie を設定
document.cookie = "session=abc123; max-age=604800; path=/; SameSite=Lax";
Cookie のストレージ上限はずっと小さく、通常 1 つの Cookie につき約 4 KB です。有効期限、パス、ドメイン、そして HttpOnly、Secure、SameSite などのセキュリティフラグを設定できます。
HttpOnly フラグは特に重要です。JavaScript からの Cookie の読み取りを阻止し、クロスサイトスクリプティング攻撃から保護します。認証トークンはほぼ常に HttpOnly Cookie であるべきです。
Set-Cookie: token=xyz789; HttpOnly; Secure; SameSite=Strict; Path=/
セッション管理と認証には Cookie が正しいツールです。サーバーが Cookie を設定し、ブラウザがリクエストごとにそれを送り返します。サーバーは JavaScript の関与なしにセッションを検証できます。
サーバーが知る必要のないクライアントサイドの状態には、Cookie は間違ったツールです。設定したすべての Cookie は、そのドメインへのすべての HTTP リクエストのサイズを増加させます。3 KB の JSON を Cookie に保存すると、そのページからのすべての画像、スタイルシート、API コールがリクエストヘッダーにその 3 KB を乗せます。
クイック判断ガイド
localStorage を使う場面:
- データがブラウザセッションをまたいで残る必要がある。
- データは JavaScript のみが使います。サーバーは必要としない。
- 4 KB 以上のストレージが必要。
- 例:ユーザー設定、再生履歴、下書きコンテンツ。
sessionStorage を使う場面:
- データはカレントタブのセッションにだけ存在すればいい。
- タブ間の隔離が必要。
- 例:フォームの状態、一時的なフィルター、ウィザードの進行状況。
Cookie を使う場面:
- サーバーがリクエストごとにデータを必要とする。
- 認証トークンやセッション ID を保存している。
- データが小さい(4 KB 未満)。
- 例:セッション ID、CSRF トークン、サーバーに送る言語設定。
大きなクライアントサイドデータに Cookie を使わないでください。HttpOnly 保護が必要な認証トークンに localStorage を使わないでください。ブラウザ再起動後も残すべきデータに sessionStorage を使わないでください。
storage タブとクロスタブ通信
見落とされがちな localStorage の機能の一つに storage イベントがあります。あるタブが localStorage の値を変更すると、同じオリジンの他のタブがイベントを受け取ります。サーバーなしでタブ間の状態を同期するのに使えます。
window.addEventListener("storage", (event) => {
if (event.key === "theme") {
applyTheme(event.newValue);
}
});
sessionStorage はこのイベントを発火しません。各タブが独立したストレージを持っているからです。Cookie も発火しませんが、ポーリングで変更を検出することはできます。
このクロスタブ挙動は便利であると同時に驚きをもたらすこともあります。あるタブで値を変更して、他のタブには見えないようにしたい場合、localStorage は間違った選択です。sessionStorage やよりスコープされた状態管理アプローチを使いましょう。
ストレージのクリアはユーザーの権利
ブラウザはユーザーが設定からサイトデータをクリアすることを許可しています。特定のサイトまたはすべてのサイトに対して、localStorage、sessionStorage、Cookie、IndexedDB、キャッシュファイルをクリアできます。つまり、アプリケーションはストレージの欠落を優雅に処理できる必要があります。
localStorage から値を読んで消えていたら、デフォルトにフォールバックしてください。sessionStorage が空なのはユーザーが新しいタブを開いたからかもしれません。クラッシュしないでください。ストレージは利便性であり、保証ではありません。
一部のブラウザは無活動期間後にサイトデータを自動的にクリアします。Safari は特に.Aggressive です。アプリケーションが重要な状態に localStorage に依存している場合、その状態がストレージのクリア後に再構築できるかどうかを検討してください。