0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

next devのメモリが突然10GBを超えて開発が固まる…犯人探しのデバッグ記録

0
Posted at

はじめに

😱「昨日まで普通に動いてたのに、急に next dev が重い…」
🫠「画面遷移のたびにメモリがどんどん増えて、最終的に固まる…」
😰「アクティビティモニタを見たら next-server が 10GB 超えてる…!?」

ある日突然、開発サーバーがメモリを食い潰して開発にならなくなりました💦

「サービスの規模が大きくなったからかな…」と最初は思ったのですが、調べていくと真犯人はソースコードでもアプリの規模でもなく、"プロジェクトの外" に紛れ込んだ 1 つのゴミファイルでした🕵️

今回は、next dev(Next.js 16 + Turbopack)のメモリ暴走をデバッグして真因にたどり着くまでの記録です🔍
同じように「dev サーバーが急に重くなった」方の助けになれば幸いです🙏

結論:親ディレクトリに紛れた「空の package-lock.json」がワークスペースルートを誤検出させていた

先に結論です。原因はこれでした👇

プロジェクトより上位のディレクトリに package-lock.json が紛れ込んでいると、Next.js がそこを「ワークスペースのルート」だと誤検出し、Turbopack が無関係なディレクトリまで丸ごと監視・走査してメモリが暴走する。

私の環境では、プロジェクトの 2 階層上に、中身が空っぽの package-lock.json(過去の誤操作の残骸)が転がっていました。

_prj/
├── package-lock.json  ← 🗑️ 中身が空のゴミ(過去の誤 npm install の残骸)
├── project/
│   └── main-app/   ← 本当のプロジェクト
│       └── package-lock.json  ← ✅ 本物
├── other-project-a/   ┐
├── other-project-b/   ├─ 無関係な兄弟プロジェクト(合計15GB超)
└── other-project-c/   ┘

このゴミファイルを削除しただけで、next-server のメモリは 10GB → 約2.5GB に激減しました⚡
コードは 1 行も変えていません。

以下、なぜこれが起きるのかと、たどり着くまでの回り道を書いていきます。

症状:遷移のたびにメモリが増え続け、最後は固まる

まず症状はこんな感じでした。

  • next dev 起動直後は普通
  • 画面を何回か遷移する(=ルートを再コンパイルする)たびに、じわじわメモリが増える📈
  • 最終的に 10GB を超え、リンクをクリックしてから遷移完了まで数十秒〜数分かかる
  • ひどいときは Mac ごとフリーズ🧊

「規模が大きくなったから重いのかな?」と思いがちですが、ページ数28・コンポーネント176 程度の中規模アプリで 10GB は明らかに異常です。

犯人探しの回り道①:「react-icons が重いんでしょ?」→ Turbopack では効かなかった

最初に疑ったのは、アイコンライブラリの react-icons でした。

「大量のアイコンを束ねたバレルファイルを import しているから、コンパイルが重いに違いない。optimizePackageImports に追加すれば直る」——そう考えたわけです。

// next.config.ts(当初やろうとした対策)
const nextConfig = {
  experimental: {
    optimizePackageImports: ['react-icons/fa6'],
  },
}

ところが、Next.js の公式ドキュメントを読んで前提が崩れました😇

Turbopack automatically analyzes imports and optimizes them. It does not require this configuration.
(Turbopack は import を自動で解析・最適化するので、この設定は不要です)

そう、Next.js 16 では next dev のデフォルトバンドラが Turbopack で、Turbopack は import を自動最適化するため、optimizePackageImports は no-op(何もしない)なんです。しかも react-icons/* はもともとデフォルトの最適化対象リストに入っています

つまり「react-icons バレル説」はそもそも的外れでした🙅

「昔の Next.js(webpack 時代)の知識」で対策すると、Turbopack では空振りすることがあります。バンドラが変わると前提も変わるので、公式ドキュメントで裏を取るのが大事でした📖

犯人探しの回り道②:AI に任せたら、逆に悪化して90GBまで暴走した話

実はこのデバッグ、Claudeにも手伝ってもらっていました🤖

次に試したのは、dev サーバーのメモリを下げる正攻法とされる preloadEntriesOnStart: false(起動時プリロードの無効化)など。多少は効きますが、10GB → 2.5GB のような劇的な改善にはなりません

さらにここで事件が起きます。Claude が検証の過程で turbopack.root を誤った値に設定したまま、dev サーバーを複数同時に起動してしまい、なんとメモリ表示が一時的に 90GB 近くまで跳ね上がって Mac がフリーズしました🧊💥(この「90GB」のカラクリは後述します)

AI に任せきりにすると、こういう"検証の暴走"も起こり得るんだな…と冷や汗をかきつつ🥶、「これは設定を小手先でいじる話じゃない。もっと根本のどこかがおかしい」と気づきます。

念のため補足すると、Claude を悪者にしたいわけではありません😌 このあとの真因特定も、実は Claude と二人三脚で辿り着いたものです。ハマるときは人間も AI もハマりますが、それでも Claude は信頼できる最強の仲間🤝 大事なのは「AI に丸投げ」ではなく「一緒に手を動かして検証する」ことだと、改めて感じました。

決定的な手がかり:起動ログの警告を見逃していた

ここで、next dev の起動ログをちゃんと読み直したら、ずっと出ていた警告に気づきました👀

⚠ Next.js inferred your workspace root, but it may not be correct.
 We detected multiple lockfiles and selected the directory of
 /Users/xxx/_prj/package-lock.json as the root directory.

「複数の lockfile を検出したので、_prj/package-lock.json のあるディレクトリをルートに選びました」

……つまり Next.js は、私のプロジェクト(main-app)ではなく、2 階層上の _prj/ をワークスペースのルートだと思い込んでいたのです😲

これが真犯人でした。

真犯人の仕組み:ワークスペースルートの誤検出

Next.js はどうやってルートを決めるのか

Next.js(Turbopack)は、「最も上位にある lockfile」をワークスペースのルートとして扱います。モノレポ対応のための挙動です。

私の環境ではこうなっていました👇

🔍 Next が上に向かって lockfile を探す
        ↓
main-app/package-lock.json   ← 見つけた(でもまだ上を探す)
        ↓
_prj/project/                    ← lockfile なし
        ↓
_prj/package-lock.json          ← 🗑️ 見つけた!(これが最上位)
        ↓
📦 「ルートは _prj/ だ!」と誤検出

誤検出すると何が起きるか

ルートが _prj/ になると、Turbopack はそのルート配下を監視・走査の対象にします。ところが _prj/ の下には、メインアプリとは無関係な別プロジェクトが15個・合計15GB超が並んでいました。

😇 本来監視すべき範囲          😱 実際に監視していた範囲
┌─────────────┐              ┌───────────────────────────┐
│ main-app/   │              │ _prj/ 全体(15GB超)        │
│  (数百MB)    │      →       │  ├ main-app/              │
└─────────────┘              │  ├ other-project-a/       │
                             │  ├ other-project-b/       │
                             │  ├ … × 15個               │
                             │  └ 全部の node_modules     │
                             └───────────────────────────┘

15GB のファイルツリーを監視し、依存グラフをメモリに抱え込もうとすれば、そりゃメモリも暴走します💥
遷移のたびに増えていくのも、Turbopack が遅延コンパイル(開いたページだけ処理)で、触るほどに巨大ツリーの解決が積み上がるからでした。

「なぜ今日、急に」問題:スケール × 2サーバー併走で閾値を超えた

ここで 1 つ疑問が残ります。

🤔「この lockfile、数か月前からあったのに、なんで今日まで平気だったの?」

調べると、構成自体(Next のバージョンもバンドラも)はずっと変わっていませんでした。罠は最初から仕込まれていたわけです。じゃあ何が変わったのか。

答えは "量" の蓄積が閾値を超えたこと。効いた要因は 2 つあり、主因はメインアプリ自身の規模でした。

  1. 【主因】メインアプリの規模が大きくなった:ページ・コンポーネントが増え、dev で扱うモジュールが増えた。ルート誤検出という土台の上でこれが膨らみ、メインアプリ単体で 約10GB に到達した
  2. 【副因】2 つ目の dev サーバーの併走:同じ親ディレクトリ配下に**管理画面用の別 Next アプリ(admin)**を作り始め、2 つの dev サーバーを同時起動するようになった

面白いのは、同じルート誤検出でもアプリの規模で結果が全然違ったこと。実測では メインアプリ ≒ 10GB / 管理画面アプリ ≒ 2GB でした。同じ 15GB ツリーを誤検出していても、小さいアプリはそこまで膨らみません(Turbopack は遅延コンパイルで、実際に食う量はアプリの規模・使い込み方に比例するため)。

つまり「開発が止まる」レベルの 10GB は主にメインアプリの規模 × ルート誤検出で生まれていて、2 サーバー併走(10GB + 2GB ≒ 12GB)は物理 18GB を超えてフリーズさせる最後のひと押し、という役割分担でした。

「規模が大きくなったから重いのでは?」という最初の直感は、実は半分正解でした。規模は主因。ただし規模そのものが 10GB を生んだのではなく、ルート誤検出が規模を何倍にも増幅していたのが実態です。

余談:18GB の Mac で「90GB」と表示されたのはなぜ?

検証中に「メモリ 90GB」と警告が出た件、気になりますよね🤔
でも冷静に考えると、私の Mac のメモリは 18GB。90GB なんて物理的に載るはずがありません。

実は OS が言う「メモリ使用量」には、"本当に RAM を使っている分" 以外もいろいろ混ざっているんです。にたとえると、こんな感じ👇

  • 🗄️ 「使うかも」と場所だけ予約した領域:実際には何も置いていないのに「確保済み」とカウントされる(=空の予約席)
  • 📄 中身はディスクにあるファイルを"参照"しているだけの領域:15GB のファイルを大量に参照すると、その分も「メモリ扱い」で大きく計上される。でも実体はディスク上にある
  • 📦 机からあふれて別の場所に逃がした分:RAM が足りなくなると、macOS は中身を圧縮したり SSD に退避したりする。これも合計に乗る

つまり「90GB を RAM に詰め込んだ」わけではありません。実態はこうでした👇

18GB の机(RAM)を使い切り、あふれた書類を SSD に出し入れし続ける。その"出し入れ"に忙殺されて、パソコン全体が固まった。

この「出し入れの渋滞」を スラッシングと呼びます。フリーズの正体はこれでした🧊

ちなみに、ps コマンドで測れる "本当に RAM に載っている量" は数十〜数百MB しかありませんでした。「実際の RAM 使用は小さいのに、警告の数字だけ巨大」という一見ちぐはぐな状況も、これで説明がつきます😌

危うくMacが吹き飛ぶんじゃないかと恐怖を覚えました…心臓に悪い…☠️

対処法

✅ 1. 余計な lockfile を削除する(本命)

プロジェクトより上位にある不要な lockfile を探して消します。

# プロジェクトより上位に lockfile が無いか探す
find ../.. -maxdepth 2 \( -name 'package-lock.json' -o -name 'pnpm-lock.yaml' -o -name 'yarn.lock' \)

出てきたファイルの中身が空っぽ("packages": {} だけ 等)で、package.json も伴っていなければ、過去の誤 npm install の残骸なので削除して OK です🗑️

rm ../../package-lock.json

これで Next の自動検出が本来のプロジェクトに戻ります。

✅ 2. ビルドキャッシュ .next を消してから再起動する

設定やルートが変わったあとは、誤ったルートがビルドキャッシュに焼き付いていることがあります。一度消してから起動しましょう。

rm -rf .next && npm run dev

再起動後、起動ログにあの警告が出ないこと・メモリが正常域(このアプリ規模で数百MB〜数GB)に収まることを確認します👌

🔧 (代替)turbopack.root で明示的に固定する

lockfile を消せない事情がある場合は、Next の警告文自身が勧めている通り、turbopack.root でルートを明示する手もあります。

// next.config.ts
const nextConfig = {
  turbopack: {
    root: process.cwd(), // プロジェクトルートに固定
  },
}

※ 設定変更後は同じく .next を消してから起動してください。

🩺 診断に使えるコマンド

# dev 稼働中の next-server の物理メモリ(RSS)を見る(KB表示)
# grep パターンを [n]ext-server にして grep 自身にマッチさせない
ps -o rss=,command= -ax | grep -i '[n]ext-server'

再発防止と教訓

同じ轍を踏まないためのチェックリストです👇

✅ dev サーバーが急に重くなったら…

1. 起動ログの「inferred your workspace root / multiple lockfiles」警告を必ず読む
   → 出ていたら、ワークスペースルート誤検出をまず疑う

2. プロジェクトより上位に余計な lockfile が無いか find で確認
   → 空のゴミ lockfile は削除

3. 複数プロジェクトを同じ親配下に並べるなら、
   → 共通の親に lockfile を作らない(両アプリが親を誤検出する)

4. 設定を変えたら .next を消してから再起動

5. Turbopack では optimizePackageImports は基本 no-op
   → 「昔の webpack 時代の対策」を鵜呑みにしない

まとめ

🎯 重要なポイント

  1. next dev が急に重くなったら、まず起動ログの警告を読むinferred your workspace root はワークスペースルート誤検出のサイン⚠️
  2. 上位ディレクトリの余計な lockfile が真犯人になり得る:Next は最上位の lockfile をルートに選ぶため、無関係な巨大ツリーまで監視してしまう🗑️
  3. 主因はアプリの規模、それをルート誤検出が増幅した:規模の成長を誤検出が何倍にも膨らませ 10GB に。2 サーバー併走はフリーズへの"最後のひと押し"✖️
  4. 「90GB」は物理 RAM ではなく仮想/mmap/スワップの会計値:実害はスラッシングによるフリーズ🧊
  5. Turbopack では optimizePackageImports は no-op:バンドラが変われば前提も変わる。公式ドキュメントで裏を取る📖

🚀 個人的な学び

  • 「重い=アプリの規模のせい」と決めつけると回り道する。まず起動ログとメモリの実測から入るべきでした👀
  • 環境の"外側"(プロジェクトの外のファイル)が原因になることがある。コードだけ見ていても見つからない🌍
  • 最終的な修正は「ゴミファイルを 1 つ消す」だけ。いちばんシンプルで正しい着地でした🍵

シンプルなメソッドや設定ほど、"どこを見て動いているか" を正しく理解しておくことがトラブル解決の近道ですね💪!

最後に

next dev のメモリ問題、原因が「プロジェクトの外」にあるとは思いませんでした🍵

皆さんも「昨日まで動いてたのに急に重くなった」系のトラブルにハマった経験はありますか🤔?
モノレポや複数プロジェクト構成でのハマりどころ、便利な診断方法などがあれば、ぜひコメントで教えてください🙌

開発環境のパフォーマンスTipsハマりポイントも共有いただけると嬉しいです🌏!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?