Deploy Error Decoder

'JavaScript heap out of memory' — how to fix it

Quick answer: FATAL ERROR: ... JavaScript heap out of memory means Node's V8 heap hit its ceiling. For a big build, raise it with NODE_OPTIONS=--max-old-space-size=4096 (MB). But if memory grows forever in a running service, that's a leak — raising the limit only delays the crash; profile the heap and fix what keeps growing instead.

What the error looks like

It's a hard crash with a V8 stack, not a catchable exception:

<--- Last few GCs --->
FATAL ERROR: Reached heap limit Allocation failed -
  JavaScript heap out of memory
 1: 0xb09... node::Abort()
 2: 0xc0f... v8::internal::Heap::FatalProcessOutOfMemory()

Two very different situations share this message: a one-off build that needs more memory than the default, and a long-running service that leaks until it dies. The fix is different for each.

Why it happens

A big build hits the default ceiling

Webpack, tsc, or a large bundle needs more than Node's default heap for that one task.

A real memory leak

A growing cache, unbounded array, or retained closures climb until the heap is exhausted.

Loading too much at once

Reading a huge file or query result fully into memory instead of streaming it.

An old default limit

Older Node defaults to roughly a 2 GB old-space, which large workloads outgrow.

Diagnose it in three steps

1

Build or runtime?

# Crashes during 'npm run build' -> build needs more heap.
# Crashes after hours of serving traffic -> suspect a leak.
2

Does it grow without bound?

node --inspect server.js   # take heap snapshots over time in DevTools
# Steadily rising retained size between snapshots = leak.
3

Raise it for the build (only)

NODE_OPTIONS=--max-old-space-size=4096 npm run build
The real fix

Raise it for builds, profile it for services

A build is a fine place to grant more memory — it runs once and exits. A long-running service is not: more heap just means it takes longer to fall over.

  • Builds: set --max-old-space-size to fit your CI box and move on.
  • Services: capture a heap snapshot under load, find the retained objects, and stream large data instead of buffering it.
  • Containers: keep the heap flag below the container memory limit so you don't just trade this crash for an OOMKilled 137.
How Infraveil handles this

Keep the service up while you find the leak

Infraveil doesn't rewrite your code, but it keeps a leaky service survivable on your own servers: the agent restarts the process when it dies, shows the crash in one place, and lets you roll back to a healthier build — buying you time to profile and fix the real cause instead of firefighting in production.

Automatic restart keeps a crashing service available while you investigate
Crashes surface in one log + status view, on servers you control
One-click rollback to the last build that didn't exhaust the heap

Frequently asked questions

How do I fix 'JavaScript heap out of memory'?

For a build, raise the limit with NODE_OPTIONS=--max-old-space-size=4096. For a running service that keeps growing, profile the heap and fix the leak — raising the limit only delays the crash.

What does --max-old-space-size do?

It sets the maximum size (in MB) of V8's old-space heap. Raising it lets memory-heavy tasks complete, but it can't fix code that leaks without bound.

Why does my build run out of memory?

Bundlers and TypeScript can need more memory than Node's default heap for large projects. Grant more for the build step specifically.

Is heap-out-of-memory the same as OOMKilled (137)?

No. Heap-out-of-memory is V8 hitting its own configured ceiling. OOMKilled (exit 137) is the OS/container killing the process for exceeding the container's memory limit. They can chain — set the heap flag below the container limit.