Troubleshooting guide · website-errors · Published 2026-08-15 · 3 min read
Node.js JavaScript heap out of memory
Fix the Node.js fatal JavaScript heap out of memory error, V8 default limits and --max-old-space-size.
- ·Read the crash
- ·Raise the limit
- ·Check for a leak
A Node.js server or build that dies with FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory is not necessarily leaking. V8 places a cap on the managed heap it gives JavaScript, and a workload that legitimately needs more memory than that cap will crash even when nothing is wrong with the code. The diagnosis is an interplay between the default limit and the actual workload, not always a bug hunt.
Read the crash
V8 reports the limit at the point of failure. The message repeats JavaScript heap out of memory after a <--- Last few GCs ---> block, and the figure printed by the garbage collector tells you what ceiling was hit and how hard the collector had to compact. A single process crashing during startup on a large dataset is often just a low default; a process that slowly grows until it dies at the same ceiling is more likely a leak.
Raise the limit
The fatal allocation is the signal that V8 allowed every long-lived object in the JavaScript heap to fill the old space. You raise that old space ceiling with --max-old-space-size, in megabytes:
node --max-old-space-size=4096 server.js
The same flag works for the common build tools that run under Node. You can also set it via the NODE_OPTIONS environment variable so it applies without editing launch scripts:
export NODE_OPTIONS="--max-old-space-size=4096"
The default is not fixed; on 64-bit machines V8 sizes the old space to roughly one to two gigabytes depending on how much RAM it sees, and Node's own documentation recommends setting it rather than relying on the default. A practical load is roughly 75 percent of available memory, leaving room for the OS, buffers, native modules and the database around the process. Setting it too high lets Node consume so much that the kernel or the OOM killer terminates the whole server, which is often worse.
Check for a leak
Raising the limit treats the symptom and is only correct when the workload truly justifies it. Confirm with a heap snapshot: if retained JavaScript objects grow steadily between requests under steady load, there is a leak and more memory just delays the crash. Look for accumulated data in module-level caches, global arrays, timers that are not cleaned up, or closures that outlive their route. If the snapshot is flat and the process simply needs more headroom, raising the limit is the right fix.
Containers change the math
In Docker or Kubernetes the process also lives under a cgroup memory cap, and the kernel can kill the container before V8 ever prints a JavaScript heap error. If a container exits with an OOMKilled status but the heap graph is flat, check the container limit, not just --max-old-space-size. Native modules, buffers and the runtime itself all consume the container budget outside the V8 heap, so leave headroom for them.
Monitoring
Set a heap limit and then watch memory in production rather than only at crash time. A steady rise toward the ceiling is an early warning that next deploy will fail. Catching a leak by monitoring, instead of by a production outage, is the difference between a scheduled fix and an emergency one.
Related guidance
If the crash happens in the browser rather than on the server, the same V8 heap story does not apply. The off-main-thread guide explains moving heavy work out of the critical path, and the heavy-JavaScript guide covers the client-side side of responsiveness.