Node.js 'JavaScript heap out of memory' (FATAL ERR)

V8 caps the heap (~4GB on 64-bit, less by default in some builds). You can raise the cap with --max-old-space-size, but the durable fix is finding what's accumulating.

What you'll see

Root causes

Genuinely large working sets (builds, big files)

Bundlers, SSR renders, and JSON parses of multi-hundred-MB files legitimately need more than the default cap. Here raising the limit is a correct fix.

Leaking caches, listeners, or unbounded arrays

Module-level Maps/arrays that only grow, event listeners never removed, promises never settling. In production this is the dangerous case — raising the limit just delays the crash.

Stream misuse — buffering whole payloads

String concatenation across chunks, or JSON.parse of an entire read file instead of streaming, multiplies memory need versus a streaming approach.

Fix it

  1. Raise the cap to get past a legitimate large job
    node --max-old-space-size=4096 server.js   # MB; for npm scripts: NODE_OPTIONS=--max-old-space-size=4096 npm run build
  2. Snapshot and compare heaps to find leaks
    kill -USR2 <pid>  # with --heapsnapshot-signal, or use node --inspect + Chrome DevTools Memory tab, compare two snapshots 10min apart
  3. Stream large inputs instead of buffering
    # use createReadStream + readline or a streaming JSON parser (clarinet/JSONStream) instead of fs.readFile + JSON.parse
  4. Bound your caches
    # replace plain Map/Array with an LRU (lru-cache) and remove listeners: emitter.removeListener(...) after use

Field note

Container OOMKills (exit 137) with heap limits set too high relative to the container memory limit is the cousin of this problem — leave headroom for buffers. --max-old-space-size sets old-space only; total RSS is always higher. Budget ~1.5x.

Common questions

Should I just keep raising --max-old-space-size?

Only for legitimate large workloads (builds, bulk processing). If memory climbs over days in a server, that's a leak — profile with heap snapshots instead of buying time with a bigger limit.

What's the default Node heap limit?

Roughly 2GB (older builds ~1.5GB) for 64-bit systems; check yours with node -e "console.log(require('v8').getHeapStatistics().heap_size_limit/1e9)". Raise it in MB via --max-old-space-size.

Ship it right the first time

Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.

Browse the template store →

One-time. Yours to modify. Instant download from the NinjaOps template store.