ローカルストレージの限界とは?容量・削除タイミング・安全性をわかりやすく解説
WebアプリやPWAを作っていると、ブラウザ側にデータを保存できる「localStorage(ローカルストレージ)」を使いたくなる場面がよくあります。
- ダークモードの設定を保存しておきたい
- 初回起動時のチュートリアルを見たかどうかを記憶させたい
- フォームの入力途中のテキストを一時保存したい
このように、サーバーと通信するまでもない「ちょっとした状態の保存」において、localStorageは非常に手軽で便利な仕組みです。
私自身、OJappやPWA LABといったWebアプリを開発・運用する中でlocalStorageを何度も活用してきましたが、実際に深く触ってみると、決して万能な金庫ではないことに気づかされます。容量は小さく、文字列しか扱えず、セキュリティ面の脆さもあり、何より「ある日突然データが消える」という落とし穴があります。
この記事では、localStorageの仕組みや容量の限界、データが削除されるタイミング、そして他のストレージとの賢い使い分けについて、開発現場の実感値を交えて分かりやすく解説します。
localStorageとは?基本の仕組み
localStorageは、ユーザーが使っているWebブラウザの中に用意されている小さなデータ保存場所です。JavaScriptを使って、数行のコードで簡単にデータの保存や読み出しができます。
// データの保存
localStorage.setItem("theme", "dark");
// データの読み出し
const theme = localStorage.getItem("theme");
この機能の最大の特徴は、「ページを閉じたり、ブラウザを落としたりしても、基本的にはデータが消えずに残り続ける」という点です。この手軽さゆえに、多くのWebアプリのUI設定などに重宝されています。
sessionStorageとの違い
localStorageとそっくりな機能に「sessionStorage(セッションストレージ)」があります。この2つの違いは、データが保持される「期間」です。
- localStorage:ブラウザを閉じても、基本的にはデータが半永久的に残る。
- sessionStorage:そのページを開いているタブやウィンドウを閉じると、データが自動で消える。
何度も繰り返し使いたい設定にはlocalStorage、今開いている画面の中だけで完結させたい一時データにはsessionStorage、と使い分けるのが基本です。
【注意】localStorageに保存できるのは「文字列」だけ
開発を始めたばかりの人が特につまずきやすいのが、「localStorageには文字列しか保存できない」という仕様です。
数値やJavaScriptのオブジェクト(連想配列)をそのまま保存しようとすると、ブラウザ側で強制的に文字列に変換されてしまい、後から読み出したときに "[object Object]" という破損した文字列になってしまう罠があります。
オブジェクトを正しく保存したい場合は、必ず JSON.stringify() を使って一度文字列に変換(シリアライズ)する必要があります。
// オブジェクトを文字列に変換して保存
const settings = { theme: "dark", fontSize: "large" };
localStorage.setItem("settings", JSON.stringify(settings));
逆に読み出すときは、 JSON.parse() を使って元のオブジェクトの形に戻します。
// 文字列をオブジェクトに戻して読み出し
const saved = localStorage.getItem("settings");
const settings = JSON.parse(saved);
この変換処理を挟む必要があるため、あまりに複雑で巨大な構造データを無理やりlocalStorageに詰め込むのは、設計としてスマートではありません。
👉 iPhoneのアイコンが更新されない理由|Safariが保持する“影キャッシュ”の正体を徹底解説 の解説が役に立ちます。
容量の限界はどれくらい?「5MB」の境界線
localStorageの容量上限は、1つの「オリジン」につき約5MiB(約5メガバイト)が目安となっています。
ここで言うオリジンとは、ざっくり言うと「同じドメイン(URLのアドレス)」のことです。例えば、同じサイトのように見えても、 http://example.com(暗号化なし)と https://example.com(HTTPS化あり)では別々のオリジン(別個の保存領域)として扱われます。
5MBは多いようで、実はかなり少ない
「ダークモードのフラグ」や「ユーザー名」などのテキストデータを保存するだけであれば、5MBは使い切れないほど広大な容量です。しかし、以下のようなデータを入れ始めると話は変わります。
- ユーザーがアップロードした画像のデータ(Base64変換したものなど)
- 数千〜数万件に及ぶ操作ログや履歴データ
- サーバーから取得した膨大なJSONオブジェクト
これらを軽い気持ちで保存していると、あっという間に容量の上限に達してしまいます。
容量を超えるとアプリがクラッシュする危険性も
万が一、5MBの容量の上限を超えてデータを保存しようとすると、ブラウザは QuotaExceededError というエラーを吐き出し、書き込み処理が強制失敗します。これにより、アプリの挙動が止まってしまうことも珍しくありません。
そのため、ユーザーが入力したデータなど、容量が膨らむ可能性のある処理を実装する際は、以下のように try...catch 文で囲んでおくのが安全な設計です。
try {
localStorage.setItem("user_data", largeData);
} catch (e) {
console.error("ストレージの容量が足りないため、保存に失敗しました", e);
// ユーザーに警告を表示するなどの処理
}
localStorageは「同期処理」だから重いデータに弱い
もう一つの技術的な盲点が、localStorageが「同期処理(非同期ではない)」で動くという点です。
JavaScriptは通常、localStorageの読み書きが完全に終わるまで、次のコードの実行をストップして待機します。データのサイズが小さければ一瞬で終わるので問題ありませんが、5MBに近い巨大なデータを頻繁に読み書きすると、その処理の最中にスマホの画面が一瞬カクついたり、ボタンの反応が悪くなったりする「UIブロック」の原因になります。この点からも、大きなデータの保存には向いていないことが分かります。
localStorageのデータは「いつ消えるのか?」
「ブラウザを閉じても残る」とされているlocalStorageですが、永遠に残り続ける保証はどこにもありません。実際には、以下のようなタイミングでデータはあっけなく削除されます。
- ユーザー自身がブラウザのキャッシュや「Webサイトデータ」を削除したとき
- プライベートブウズ(シークレットモード)のタブを閉じたとき
- スマホ端末全体の空き容量(ストレージ)が逼迫し、OSやブラウザが「不要なデータ」として自動クレンジングしたとき
- Safari(iOS)独自のクッキー・トラッキング防止機能(ITP)などの影響を受けたとき
特にiPhone(Safari)環境では注意が必要
私自身も実機検証やユーザーからの報告で痛感したことですが、iPhoneのSafari環境はプライバシー保護の観点からストレージの永続化に対してかなりシビアです。特に、一定期間アクセスがないサイトのローカルデータが、OS側の判断で自動的に消去される仕様が存在します。
ホーム画面に追加したPWAアプリの場合、Safari本体とは保存領域の扱いが異なり少し消えにくい傾向はありますが、それでも「絶対に消えない」という永続の保証はありません。そのため、「消えたら絶対に困る唯一無二のマスターデータ」をlocalStorageだけに保存する設計は絶対に避けるべきです。
PWAやWebアプリ開発における、正しいストレージの使い分け
では、消えたら困るデータや、大きなファイルはどこに保存すべきなのでしょうか?ブラウザにはlocalStorage以外にもいくつかの保存領域が用意されています。これらを正しく役割分担させるのが、堅牢なアプリを作るコツです。
| ストレージ名 | 得意なデータ・役割 | 処理方式 | 容量の目安 |
|---|---|---|---|
| localStorage | UI設定(ダークモード等)、一時的な状態の保持 | 同期処理 | 約5MB(極小) |
| IndexedDB | 構造化データ、大量のJSON、過去の履歴、オフライン用データ | 非同期処理 | 端末容量の数十%など(大容量) |
| Cache API | PWA用のHTML、CSS、JavaScript、画像ファイルなどのアセット | 非同期処理 | 端末容量の数十%など(大容量) |
| Cookie | サーバーとのセッション管理、ログイン状態の維持(自動送信される) | – | 約4KB(極小) |
※また、JavaScriptから簡単に中身を読み取ることができるlocalStorageは、XSS(クロスサイトスクリプティング)などの脆弱性攻撃を受けた際に、中のデータを丸ごと盗まれる危険性があります。そのため、セッショントークン(重要な認証情報)や個人情報、決済情報などを生データで保管するのもセキュリティ上厳禁です。
【現場の知見】localStorageを安全に使うための実装ポイント
私の経験上、localStorageと付き合う際は以下のルールを徹底するとトラブルを未然に防げます。
- データ構造に「バージョン(version)」を持たせる
アプリのアップデートに伴ってJSONの構造(キーの名前など)を変更した際、ユーザーのブラウザに古い構造のlocalStorageが残っていると、コードがエラーを起こして画面が真っ白になることがあります。保存データにversion: 1のような目印をつけておき、コード側で古いバージョンを検知したら自動でデータをクレンジング・移行する仕組みを入れておくと安全です。 - 消えてもいつでも初期状態に復旧できるようにする
「localStorageが消えている=エラー」にするのではなく、消えていたらデフォルトの設定(例:ライトモード)でアプリが問題なく立ち上がるように、フォールバック(代替処理)を必ず用意しておきます。
関連記事
- ブラウザへのローカル保存の基礎をもっと易しく知りたいなら:
ローカル保存とは?キャッシュ・Cookieの違いをやさしく解説 - 画像やアセットを効率よく保存するブラウザキャッシュの仕組み:
ブラウザキャッシュの仕組みを徹底解説 - Service Workerと連動したPWAの高度なデータ保持戦略:
PWAのキャッシュ戦略を完全に理解する
hr>
まとめ:localStorageは「手軽なメモ帳」として使おう
localStorageは、手軽に扱える反面、容量制限(5MB)や自動削除のリスク、同期処理によるパフォーマンス低下など、意外と制約の多い保存場所です。
イメージとしては、厳重な「金庫」ではなく、机の上の「小さなメモ帳」として扱うのが正解です。
- 消えても致命傷にならない、ユーザー体験を少し良くするための軽いUI設定だけを入れる。
- 画像や大きな構造化データは IndexedDB や Cache API へ切り替える。
- 消えたら困る重要なデータや認証情報は、必ず暗号化してサーバー(データベース)側で集中管理する。
この特性と役割分担を正しく理解しておくことで、ユーザーにとっても開発者にとっても、データがズレない安全で快適なWebアプリ・PWAを構築できるようになります!