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.
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.
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.
String concatenation across chunks, or JSON.parse of an entire read file instead of streaming, multiplies memory need versus a streaming approach.
node --max-old-space-size=4096 server.js # MB; for npm scripts: NODE_OPTIONS=--max-old-space-size=4096 npm run build
kill -USR2 <pid> # with --heapsnapshot-signal, or use node --inspect + Chrome DevTools Memory tab, compare two snapshots 10min apart
# use createReadStream + readline or a streaming JSON parser (clarinet/JSONStream) instead of fs.readFile + JSON.parse
# replace plain Map/Array with an LRU (lru-cache) and remove listeners: emitter.removeListener(...) after use
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.
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.
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.
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.