JavaScript heap out of memory (Node FATAL ERROR near heap limit)

V8 hit the ceiling it set for itself. The machine may still have free RAM — Node just refused to grow its JavaScript heap any further.

What the error looks like

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x… node::Abort() …
 2: 0x… v8::Utils::ReportOOMFailure …

Sometimes shortened to JavaScript heap out of memory in CI logs. It is a V8 abort, not a normal Error you can try/catch.

V8 heap vs system RAM

LimitWho enforces itWhat you see
V8 old-space heapNode / V8 (--max-old-space-size)FATAL ERROR … heap out of memory
Container / cgroup memoryDocker, Kubernetes, systemdExit 137, OOMKilled
Host RAM + swapLinux OOM killerAlso 137; dmesg shows "Killed process"

Default old-space is roughly 1.5–4 GB depending on Node version and whether the host looks "small". A 16 GB laptop can still throw heap OOM at ~2 GB because V8 never asked for more. Conversely, setting --max-old-space-size=8192 inside a 1 GB container will get you killed with 137 before V8 complains.

Raise the limit (when it is appropriate)

# One-off
node --max-old-space-size=4096 server.js
node --max-old-space-size=8192 ./node_modules/webpack/bin/webpack.js

# Sticky for child processes (npm scripts, CLIs)
export NODE_OPTIONS=--max-old-space-size=4096
npm run build

# package.json script
"build": "NODE_OPTIONS=--max-old-space-size=4096 next build"

When raising the limit is the wrong fix

Chrome DevTools / heap snapshots (brief)

  1. Run with inspect: node --inspect server.js (or --inspect-brk).
  2. Open chrome://inspect → your process → Memory → Take heap snapshot.
  3. Compare two snapshots after reproducing growth; sort by "Shallow size" / "Retained size". Look for detached DOM nodes (rare in pure Node), ever-growing Maps/Arrays, caches without bounds, and large strings.
  4. Clinic.js Heapprofiler / node --heapsnapshot-signal=SIGUSR2 also work on servers without a browser UI.

Docker and small VMs

# Compose / run — give the container enough RAM, then size V8 under it
docker run -m 2g -e NODE_OPTIONS=--max-old-space-size=1536 myimage
# Kubernetes: resources.limits.memory + the same NODE_OPTIONS

If builds only fail in CI: use a larger runner, reduce parallelism, or build artefacts elsewhere and copy them in. See also exit 137 when the cgroup limit wins first.

CRA / Next / webpack tips

Mystery binary or lockfile blob? What is this?

Related

Killed: exit code 137 (OOM) · Node OpenSSL digital envelope error · EADDRINUSE · ENOSPC no space left · EMFILE too many open files

Questions

What does JavaScript heap out of memory mean?

V8's JavaScript heap hit --max-old-space-size (or the default). The process aborts with FATAL ERROR. The machine may still have free RAM.

How do I fix heap out of memory in Node?

Try NODE_OPTIONS=--max-old-space-size=4096 for builds. If it keeps growing at runtime, find the leak or huge allocation instead of only raising the limit.

What is the difference between heap OOM and exit 137?

Heap OOM is V8 refusing to grow. Exit 137 is SIGKILL from the Linux OOM killer or a container memory limit — the whole process RSS was too big.

Is NODE_OPTIONS=--max-old-space-size safe?

Yes for a controlled build or service, if the value fits under the container/VM limit. Do not set it larger than available memory or every Node child will compete for RAM.

Why does my Next/webpack build run out of memory?

Bundlers hold large graphs, transforms and source maps in heap. Raise the limit for the build, upgrade the tool chain, enable caching, or build on a bigger machine.

How do I take a Node heap snapshot?

Start with node --inspect, open chrome://inspect, Memory tab → Take heap snapshot. Compare two snapshots to see what grew.

Published .

Try it

Related guides

Newest guides