勉強記録アプリをVercelでデプロイしようとGitHubと連携してインポートしたら、エラーが発生しました。DBも使わないし、簡単なコードで作ったアプリなのに「なんで?」という感じでかなり混乱しました。
エラー内容はこちらです。
ReferenceError: localStorage is not defined
今回は、実際に自分がハマった原因と解決方法を簡単にまとめてみます。
- Vercelデプロイ時に
localStorage is not definedエラーが発生する原因 - なぜローカル環境では動くのにVercelではエラーになるのか
typeof window === "undefined"を使った対処方法useEffectを使って安全に localStorage を扱う方法- localStorage エラーが発生した時の確認ポイント
発生した状況
ブログでも紹介していたNext.jsで勉強記録アプリをデプロイしようとしました。勉強時間を保存するために localStorage を使っていたのですが、ローカルでは問題なく動いていました。ですが、Vercelにデプロイするとエラーが発生。最初はVercelの設定ミスかと思ったのですが、原因は別のところにありました。
原因
Next.jsは、ブラウザ(CSR)だけでなくサーバー側(SSR/Build時)でもコードを実行します。 しかし、localStorage はブラウザの中にしか存在しない機能(Web API)です。
つまり、サーバー側でページを組み立てている段階で localStorage を読み込もうとして、「そんなもの知らないよ!」と ReferenceError: localStorage is not defined エラーを出してビルドにに失敗していました。

自分は最初、この「サーバー側でも実行される」という感覚があまり理解できておらず、「ブラウザで使えるなら全部使える」と思っていました(😂)
今回は3箇所で同じ問題が発生していました
① localStorageへ保存する関数がサーバーでも実行されていた
まず1つ目は、localStorage にデータを保存する関数です。最初は特に何も考えずそのまま書いていました。
ですが、Vercelではサーバー側でも実行される可能性があるため、ブラウザ環境かどうかを確認する必要がありました。
修正後はこちらです。
// この一行を先頭に入れることで、サーバー環境では処理をスキップさせます。
if (typeof window === "undefined") return;
最初にこれを追加することで、サーバー環境では処理を終了するようにしました。
② getStudyData関数でもサーバー実行を防ぐ必要があった
保存されたデータを取得する getStudyData() 関数も同様です。関数の中で localStorage を使用していたため、サーバー側で実行されるとエラーになります。
そのため、こちらも同じようにサーバーでは実行されないよう修正しました。
// サーバー環境なら空のオブジェクトを返して安全に終了
if (typeof window === "undefined") {return {} ;}③ localStorageから直接データを取得していた
最後の問題は、コンポーネント内で直接 getStudyData() を実行していたことです。
最初はこのように書いていました。
//修正前
const studyData = getStudyData();
ですが、これだとVercelではgetStudyData() がサーバー側で実行される可能性があります。
そこで、初期値は空のStateにしておき、ブラウザ側に画面が描画された直後(マウント後)に実行される useEffect の中でデータを取得するように変更しました。
//修正後
const [studyData, setStudyData] = useState<StudyData>({});
useEffect(() => {
// useEffectの中は必ずブラウザ側(Client)で実行されるため安全!
const data = getStudyData();
setStudyData(data);
}, []);
localStorage エラーが出たら確認するポイント
今回のエラーを解決する中で、確認したポイントをまとめてみました。
| 確認項目 | チェック内容 |
|---|---|
| localStorageを直接使っていないか | localStorage.getItem() や localStorage.setItem() をコンポーネントのレンダリング中に実行していないか確認する |
| windowチェックがあるか | typeof window !== "undefined" を使ってブラウザ環境か確認する |
| useEffectを使っているか | 初回データ取得は useEffect の中で行う |
| Stateで管理しているか | 取得したデータは state に保存して利用する |
| “use client” が付いているか | Client Component として動作するように設定する |
今回の対応フロー
今回、自分は次の流れで原因を特定して修正しました。
localStorage is not defined エラー発生
↓
localStorage を使っている箇所を探す
↓
保存処理に window チェックを追加
↓
取得処理(getStudyData)にも window チェックを追加
↓
コンポーネント内の直接実行をやめる
↓
useEffect でデータ取得
↓
取得したデータを state で管理
↓
Vercelで再デプロイ
↓
解決!
もし Vercel や Next.js で localStorage is not defined エラーが発生した場合は、まず「サーバー側で localStorage を参照していないか?」を確認してみると解決のヒントになるかもしれません。
終わりに
今回のエラーを通して、
- Next.jsではサーバー側でもコードが実行される
localStorageはブラウザ専用- データ保存だけでなく取得時も注意が必要
useEffectの実行タイミングが重要
ということを学びました。
最初はかなり混乱しましたが、実際に修正しながらSSRとCSRの違いを少し理解できた気がします。同じように localStorage is not defined エラーで困っている方の参考になれば嬉しいです。
関連記事
今回のエラーは、下記の勉強記録アプリをデプロイした際に発生したものです。アプリの実装内容について興味がある方は、こちらの記事もご覧ください。
【Next.js】Githubのような勉強記録アプリ①:簡単なTimer実装
【Next.js】Githubのような勉強記録アプリ②:LocalStorageを活用したデータ保存
【Next.js】Githubのような勉強記録アプリ③:Gridを使って勉強時間を可視化する
【Next.js】Githubのような勉強記録アプリ④:LocalStorageに詳細を追加・変更しよう
Vercelデプロイ方法についてはこちらをご参考ください。(DBなし)

