Fix 'FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory' in Node.js

intermediate๐Ÿ’š Node.js2026-03-18| Node.js (all versions), Linux / macOS / Windows, any Node.js application or build tool (webpack, Next.js, etc.)

Error Message

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
#nodejs#memory#heap#v8#performance

TL;DR โ€” Quick Fix

Run your script with a larger heap:

node --max-old-space-size=4096 your-script.js

Or set it via environment variable โ€” handy for build tools where you can't easily edit the command directly:

export NODE_OPTIONS="--max-old-space-size=4096"
npm run build

Replace 4096 (4 GB) with a value that fits your machine. Common values: 2048, 4096, 8192.

What Causes This Error

Node.js runs on the V8 engine, which caps heap memory to prevent runaway processes. On 64-bit systems the default limit is roughly 1.5 GB; on 32-bit systems, about 512 MB. Exceed that ceiling, and the process dies immediately with:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory

The usual suspects:

  • Building large front-end projects โ€” webpack, Next.js, and Create React App are notorious for this
  • Processing large files or datasets entirely in memory
  • Memory leaks: objects that keep accumulating and never get garbage-collected
  • Recursive functions that don't terminate correctly
  • Running several heavy operations at the same time

Fix 1: Increase the V8 Heap Limit

Start here. It's a one-liner and usually unblocks you immediately.

Directly in the command

node --max-old-space-size=4096 server.js

Via NODE_OPTIONS (recommended for build scripts)

# Linux / macOS
export NODE_OPTIONS="--max-old-space-size=4096"
npm run build

# Windows (Command Prompt)
set NODE_OPTIONS=--max-old-space-size=4096
npm run build

# Windows (PowerShell)
$env:NODE_OPTIONS="--max-old-space-size=4096"
npm run build

In package.json scripts

{
  "scripts": {
    "build": "node --max-old-space-size=4096 node_modules/.bin/webpack",
    "start": "node --max-old-space-size=4096 server.js"
  }
}

Choosing the right value

Aim for about 75% of your available RAM. Check what you have first:

# Linux
free -m

# macOS
sysctl hw.memsize

# Windows
wmic OS get TotalVisibleMemorySize

On an 8 GB machine, --max-old-space-size=6144 is a reasonable ceiling. Don't allocate the full amount โ€” the OS and other processes need headroom too.

Fix 2: Find and Fix Memory Leaks

Bumping the heap is a band-aid. If the process grows without stopping, it will crash again โ€” just at a higher number. You need to track down the leak.

Generate a heap snapshot

node --inspect your-script.js

Open chrome://inspect in Chrome, click Open dedicated DevTools for Node, then go to the Memory tab. Take a snapshot, let the app run a while, take another. Look for object types that keep piling up between snapshots โ€” those are your leak candidates.

Monitor heap usage in real time

const v8 = require('v8');

setInterval(() => {
  const stats = v8.getHeapStatistics();
  const usedMB = Math.round(stats.used_heap_size / 1024 / 1024);
  const totalMB = Math.round(stats.heap_size_limit / 1024 / 1024);
  console.log(`Heap: ${usedMB} MB used / ${totalMB} MB limit`);
}, 5000);

Watch the numbers. A healthy process plateaus after warm-up. If usedMB keeps climbing with no ceiling, something is holding references it shouldn't.

Common leak patterns

  • Event listeners not removed โ€” call emitter.removeListener() or emitter.off() once the listener is no longer needed
  • Closures capturing large objects โ€” long-lived callbacks that reference big variables prevent the garbage collector from freeing them
  • Unbounded in-memory caches โ€” swap plain objects or Maps for a size-limited cache like lru-cache
  • Unhandled promise rejections โ€” rejected promises that are never caught can quietly accumulate over time
# Install a lightweight memory profiler
npm install --save-dev clinic
npx clinic heapprofiler -- node your-script.js

Fix 3: Process Data in Streams, Not All at Once

Loading a 500 MB file into a variable is an instant recipe for this crash. Streams read and discard data as they go โ€” heap usage stays flat:

const fs = require('fs');
const readline = require('readline');

const rl = readline.createInterface({
  input: fs.createReadStream('large-file.txt'),
  crlfDelay: Infinity
});

rl.on('line', (line) => {
  // process one line at a time โ€” no giant array in memory
  processLine(line);
});

When you must work with an array, process it in batches:

async function processInChunks(array, chunkSize, fn) {
  for (let i = 0; i < array.length; i += chunkSize) {
    const chunk = array.slice(i, i + chunkSize);
    await fn(chunk);
  }
}

A chunk size of 100โ€“500 items is a good starting point โ€” enough to keep throughput high without spiking memory.

Verify the Fix

Confirm the new limit is actually in effect before re-running your build:

node -e "const v8 = require('v8'); console.log(v8.getHeapStatistics().heap_size_limit / 1024 / 1024 + ' MB');"

# After setting --max-old-space-size=4096, expected output:
# 4096 MB

Re-run the command that was crashing. If it still fails at the higher limit, the root cause is a memory leak โ€” go back to Fix 2.

Further Reading

Related Error Notes