ブラウザにデータを保存する localStorage と sessionStorage は、どちらも同じ Web Storage API で操作方法もほぼ同じです。違いは保存期間とスコープ(どこまでデータが共有されるか)、そしてstorage イベントの挙動にあります。この記事では両者の違いと、何をどちらに保存すべきかの判断基準を整理します。
- 共通のAPIと、文字列しか保存できない点(JSON)
- 保存期間・スコープの違いと比較表
storageイベントの発火差(タブ間同期の可否)- Cookie・IndexedDB を含めた保存先の使い分け
- どちらに何を保存すべきかの判断ガイド
localStorage、そのタブ・その訪問だけでよいデータ(入力途中・確認画面)は sessionStorage。タブ間で同期したいなら localStorage + storage イベント、サーバーにも送りたいなら Cookie を選びます。共通点:操作方法は同じ(Web Storage API)
どちらも setItem / getItem / removeItem / clear の同じメソッドで操作します。getItem はキーが無ければ null を返します。
// localStorage の例
localStorage.setItem("theme", "dark");
const theme = localStorage.getItem("theme"); // 無ければ null
localStorage.removeItem("theme");
localStorage.clear(); // 全削除
// sessionStorage もまったく同じメソッド
sessionStorage.setItem("draft", "入力中の内容");
const draft = sessionStorage.getItem("draft");
どちらも値は文字列のみです。オブジェクトや配列をそのまま渡すと
"[object Object]" のような文字列に変換されてしまいます。JSON.stringify で保存し、JSON.parse で戻します。const user = { name: "佐藤", theme: "dark" };
// 保存:文字列化する
localStorage.setItem("user", JSON.stringify(user));
// 取得:パースして戻す(無ければ {} にフォールバック)
const saved = JSON.parse(localStorage.getItem("user") || "{}");
localStorage:閉じても残る(永続)
localStorage はブラウザを閉じても残り、明示的に削除するまで保持されます。同一オリジンなら、別タブからも同じデータを参照できます。ユーザー設定・テーマカラー・「次回から表示しない」状態などの保存に向いています。
sessionStorage:タブを閉じるまで(一時的)
sessionStorage はそのタブを閉じると消えます。新しいタブやウィンドウは別セッションとみなされ、データは共有されません。リロードでは保持され、入力途中の一時保存や確認画面用の値に向いています。
sessionStorage はリロードでは残りますが、新しいタブには引き継がれません(タブを複製した場合は複製時点の内容がコピーされることがあります)。「このタブのこの訪問だけ」というスコープだと考えると分かりやすいです。違いの比較表
| 項目 | localStorage | sessionStorage |
|---|---|---|
| 有効期限 | 明示的に削除するまで永続 | タブ/ウィンドウを閉じるまで |
| スコープ | 同一オリジンの全タブで共有 | そのタブ内だけ |
storage イベント |
他タブで発火する | 他タブへ伝播しない |
| 容量の目安 | 約5MB | 約5MB |
| サーバー送信 | されない | されない |
| 主な用途 | 設定・テーマ・状態の永続 | 入力途中・確認画面の一時データ |
最大の実用差:storage イベント(タブ間同期)
見落とされがちですが、両者の重要な違いが storage イベントです。localStorage の変更は、同じオリジンの他のタブで storage イベントを発火します。これを使えば、片方のタブでのテーマ変更を他のタブへ即時反映できます。sessionStorage はタブをまたがないため、この方法でのタブ間同期はできません。
// 別タブで localStorage が変わると発火(変更した自分のタブでは発火しない)
window.addEventListener("storage", (e) => {
if (e.key === "theme") {
console.log("他タブでテーマが変更されました:", e.newValue);
applyTheme(e.newValue);
}
});
JSON保存・有効期限付きキャッシュ・容量例外処理・
storage イベントでのタブ間通信の実装例はlocalStorageの使い方完全ガイドに詳しくまとめています。入力内容の一時保存・復元(sessionStorage 的な用途)はフォーム入力内容をローカルストレージに保存する方法も参考になります。Cookie・IndexedDB との使い分け
ブラウザの保存先は Web Storage だけではありません。サーバーにも送りたいなら Cookie、大量・構造化データやオフライン対応なら IndexedDB が向きます。
| 保存先 | 容量の目安 | 期限 | サーバー送信 | 向く用途 |
|---|---|---|---|---|
| localStorage | 約5MB | 永続 | されない | 設定・状態の永続 |
| sessionStorage | 約5MB | タブを閉じるまで | されない | 一時データ |
| Cookie | 約4KB | 期限を指定 | 毎回される | 認証トークン・サーバー連携 |
| IndexedDB | 大容量 | 永続 | されない | 大量/構造化データ・オフライン |
Cookieは毎回のリクエストに自動で付くため、サーバー側で読みたい値(ログイン状態など)に向きます。ただし容量が小さく、送信のたびに通信量が増える点に注意します。Cookieの具体的な操作はCookie の取得・設定・削除の方法を参照してください。
どちらに保存すべきか:判断ガイド
- 閉じても残したい(テーマ・設定・既読状態)→
localStorage - このタブの今だけ(入力途中・ウィザードの一時値)→
sessionStorage - 複数タブで同期したい →
localStorage+storageイベント - サーバーでも読みたい(認証)→ Cookie
- 大量・構造化データ/オフライン → IndexedDB
セキュリティと容量の注意
localStorage / sessionStorage は暗号化されておらず、JavaScriptから誰でも読めます。XSSの脆弱性があるとトークンや個人情報を盗まれるため、パスワード・認証トークン・個人情報は保存しないでください。また容量(約5MB)を超えると
QuotaExceededError が発生するため、大きなデータを扱うときは try / catch で例外を処理します。よくある質問(FAQ)
localStorage はブラウザを閉じても永続し、同一オリジンの全タブで共有されます。sessionStorage はそのタブを閉じると消え、他のタブとは共有されません。JSON.stringify で文字列化して保存し、取り出すときに JSON.parse で戻します。localStorage を使い、window.addEventListener("storage", ...) で他タブの変更を受け取ります。sessionStorage はタブをまたがないため、この方法では同期できません。QuotaExceededError が発生するので try / catch で処理します。まとめ
- 操作は共通:
setItem/getItem。値は文字列のみ(オブジェクトはJSON) - localStorage:永続・全タブ共有・
storageイベントが他タブで発火 - sessionStorage:タブを閉じるまで・そのタブ限定
- Cookie:サーバー送信あり・約4KB。IndexedDB:大容量・構造化
- 機密情報は保存しない。容量超過は
QuotaExceededErrorを処理
保存期間・スコープ・タブ間同期の必要性で選べば、用途に合った安全な保存先を選択できます。

