FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory は、Node.js が JavaScript のデータを置くメモリ(ヒープ)の上限に達し、それ以上確保できずに強制終了したときのエラーです。 ビルド(webpack・Vite・Next.js・TypeScript)や、大きなファイル・大量のデータを扱う処理で起きます。

対処は2段階です。

段階 やること
1. すぐに動かす ヒープの上限を上げる:NODE_OPTIONS=--max-old-space-size=4096(単位は MB)
2. 原因を減らす 全部を一度にメモリに載せる処理を、少しずつ処理する形にする。もれがないかをヒープスナップショットで確かめる

確認環境:Node.js 22.22.2、Linux(メモリ 8GB)(確認日 2026年10月11日)。ヒープの上限を小さくして再現しました。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「JavaScript heap out of memoryの直し方|Node.js」

再現:配列にデータを入れ続ける

const rows = [];
let i = 0;
while (true) {
  rows.push({ id: i, name: "user" + i, tags: ["a", "b", "c"], created: new Date().toISOString() });
  i++;
}
$ node --max-old-space-size=64 leak.js
200000 件 heapUsed=39MB

<--- Last few GCs --->
[4596:0x381be000]  981 ms: Mark-Compact (reduce) 62.3 (66.1) -> 62.3 (66.1) MB, ...
[4596:0x381be000] 1036 ms: Mark-Compact (reduce) 62.8 (66.1) -> 62.6 (66.3) MB, ...

<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
----- Native stack trace -----
 1: 0xe42d60 node::OOMErrorHandler(char const*, v8::OOMDetails const&) [node]
 ...
$ echo $?
134
表示 読み方
Last few GCs の 62.3 -> 62.3 MB ガベージコレクション(不要なメモリの回収)をしてもほとんど減らない=使い続けているデータでいっぱい
Mark-Compact (reduce) が続く 回収を何度も試みている。直前は処理がとても遅くなる
終了コード 134 強制終了(abort)。try/catch では捕まえられない

まず確認:今のヒープの上限はいくつか

node -e "console.log(Math.round(require('v8').getHeapStatistics().heap_size_limit / 1048576) + 'MB')"
条件(確認環境) heap_size_limit
何も指定しない(メモリ 8GB のマシン) 2096MB
--max-old-space-size=256 304MB
--max-old-space-size=4096 4144MB

既定の上限は、マシンのメモリによって決まります(Node.js 公式の学習ガイドでも、上限はシステムのメモリに基づくとされています)。指定した値より少し大きく表示されるのは、--max-old-space-size が「長く使うデータの領域(Old Space)」だけの上限で、ほかの領域が足されるためです。

NODE_OPTIONS がどこかで設定されていないか

確認環境では、環境変数 NODE_OPTIONS に --max-old-space-size=8192 が設定されていたため、何も指定していないつもりでも上限は 8GB 台になっていました。CI・Docker のイメージ・シェルの設定ファイルで設定されていることがあります。

node -p "process.env.NODE_OPTIONS"

直し方1:ヒープの上限を上げる

実行のしかた 書き方
node を直接実行 node --max-old-space-size=4096 app.js
npm scripts・ビルドツール NODE_OPTIONS=--max-old-space-size=4096 npm run build
package.json に書く "build": "NODE_OPTIONS=--max-old-space-size=4096 vite build"(Windows も使うなら cross-env を使う)
PowerShell $env:NODE_OPTIONS="--max-old-space-size=4096"; npm run build
GitHub Actions env: に NODE_OPTIONS: --max-old-space-size=4096

npm run build のように、node を直接実行しない場合は NODE_OPTIONS を使います。確認環境でも、NODE_OPTIONS=--max-old-space-size=512 npm run ... で起動した node の上限は 560MB になり、npm が起動する node に引き継がれました。

NODE_OPTIONS とコマンドラインの両方に書いたとき

$ NODE_OPTIONS=--max-old-space-size=256 node --max-old-space-size=1024 -e "..."
1072                           ← コマンドラインの 1024 が使われた

両方にあると、コマンドラインの指定が使われました。 上限を上げたのに変わらないときは、コマンドライン側に小さい値が書かれていないかも確かめます。

いくつにするか

目安 理由
マシン(コンテナ)のメモリより小さく ヒープのほかにも、Node.js 自体・ネイティブのメモリ・ほかのプロセスがメモリを使う
CI のランナーのメモリを確かめる ランナーのメモリを超えると、Node.js のエラーではなく OS やコンテナに強制終了される
上げても落ちるなら、上げるのをやめて原因を探す もれ(使い終わったデータが解放されない)なら、いくら上げても落ちる

直し方2:全部を一度に載せない

44MB・200万行の CSV を合計する処理で比べました。

// 全部読み込んでから処理する
const lines = fs.readFileSync(file, "utf8").split("\n").slice(1).filter(Boolean);
const rows = lines.map(l => { const [id, name, amount] = l.split(","); return { id: +id, name, amount: +amount }; });
console.log("合計", rows.reduce((s, r) => s + r.amount, 0));
// 1行ずつ読みながら処理する
const rl = readline.createInterface({ input: fs.createReadStream(file) });
let total = 0, first = true;
for await (const line of rl) {
  if (first) { first = false; continue; }   // 見出し行
  if (!line) continue;
  total += +line.split(",")[2];
}
書き方 ヒープの上限 128MB ヒープの上限 1024MB
全部読み込む(readFileSync → split → map) JavaScript heap out of memory 成功
1行ずつ読む(stream + readline) 成功(heapUsed=5MB) 成功

44MB のファイルでも、文字列の配列とオブジェクトの配列にすると、何倍ものメモリを使います。 1行ずつ処理すれば、ファイルが大きくなってもメモリはほとんど増えません。

起きやすい処理 見直し方
大きなファイル・CSV・JSON を readFileSync で読む stream で少しずつ処理する
DB から全件を取得して配列にする ページングする、またはカーソル・stream で読む
結果を全部配列にためてから書き出す 処理しながら書き出す
キャッシュ用のオブジェクト・Map が増え続ける 上限や有効期限を決める
ビルド(TypeScript の型チェック・ソースマップ) 型チェックを別のプロセスに分ける、ソースマップの設定を見直す

原因を探す:落ちる直前のヒープスナップショット

--heapsnapshot-near-heap-limit を付けると、上限に近づいたときに、ヒープの中身をファイルに書き出します。

$ node --max-old-space-size=64 --heapsnapshot-near-heap-limit=1 leak.js
Wrote snapshot to /srv/s4/Heap.20261011.002514.4928.0.001.heapsnapshot
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

書き出された .heapsnapshot を、Chrome の DevTools の Memory タブで「Load」して開くと、何のオブジェクトがメモリを使っているかが分かります(Node.js 公式の学習ガイドの手順)。確認環境では、64MB のヒープに対してスナップショットは約 156MB になりました。ディスクの空きを確かめてから使います。

確認の手順(チェックリスト)

順番 確認すること 方法
1 今の上限 v8.getHeapStatistics().heap_size_limit
2 NODE_OPTIONS の設定 node -p "process.env.NODE_OPTIONS"
3 まず動かす NODE_OPTIONS=--max-old-space-size=4096(マシンのメモリより小さく)
4 全部を一度に載せていないか readFileSync・全件取得・配列にためる処理
5 もれがないか --heapsnapshot-near-heap-limit=1 で書き出し、DevTools で開く
6 CI・コンテナ ランナー・コンテナのメモリと、上限の値を合わせる

よくある質問

Q. 上限を上げたのに、まだ落ちます。 A. 使い終わったデータが解放されない「もれ」の可能性があります。上限を上げると落ちるまでの時間が延びるだけなので、ヒープスナップショットで、何が増え続けているかを確かめます。

Q. try / catch で捕まえて続けられますか。 A. できません。このエラーは JavaScript の例外ではなく、Node.js のプロセスそのものが強制終了します(確認環境の終了コードは 134)。サーバーなら、プロセスの再起動の仕組み(PM2・systemd・コンテナの再起動)と、原因の対処を組み合わせます。

まとめ

  • Node.js のヒープ(JavaScript のメモリ)が上限に達して強制終了。try/catch では捕まえられない
  • まず heap_size_limit と NODE_OPTIONS で今の上限を確かめる
  • すぐ動かすなら NODE_OPTIONS=--max-old-space-size=4096(単位 MB、マシンのメモリより小さく)
  • コマンドラインの指定は NODE_OPTIONS より優先された
  • 根本は 全部を一度に載せない。stream で1行ずつ処理すると、128MB でも動いた
  • もれは --heapsnapshot-near-heap-limit で書き出して、DevTools の Memory タブで探す

参考・出典

確認日はいずれも 2026年10月11日です。

  • Node.js「Understanding and Tuning Memory」:https://nodejs.org/en/learn/diagnostics/memory/understanding-and-tuning-memory
  • Node.js「Using Heap Snapshot」:https://nodejs.org/en/learn/diagnostics/memory/using-heap-snapshot

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「JavaScript heap out of memoryの直し方|Node.js」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?