Blog
5 min read

"JavaScript Heap Out of Memory": Why It Happens and How to Fix It

FATAL ERROR: Reached heap limit — JavaScript heap out of memory. What Node's heap limit is, why builds and servers hit it, how to raise it safely with --max-old-space-size, when the real problem is a memory leak, and the difference from exit code 137.

Your build, your tests or your server suddenly dies with:

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

It's common during npm run build on large projects, in CI, and on small servers. Sometimes the fix is one setting; sometimes it's a sign of a real problem. Here's how to tell.

What the heap is

Node.js stores your program's objects, strings and arrays in an area of memory called the heap. Node sets a maximum heap size. When the program needs more than that and the garbage collector can't free enough, Node gives up and crashes with this error.

The default limit depends on your Node version and how much memory the machine (or container) has. It's usually a few gigabytes at most, and it can be smaller on small servers and CI machines.

Step 1: Work out what's running out

Ask: which process crashed, and when?

  • During a build (next build, vite build, tsc, webpack): large projects, especially with TypeScript type-checking and source maps, can genuinely need more memory than the default. Often a legitimate need.
  • During tests: a test runner holding many test files in memory, or a leak in the code under test.
  • A running server, after hours or days: this pattern — memory growing until it crashes — almost always means a memory leak.
  • A script processing a big file or query: loading everything into memory at once.

Fix 1: Raise the limit (when the need is real)

For builds and tools that legitimately need more memory, raise the heap limit with --max-old-space-size, in megabytes:

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

On Windows PowerShell:

$env:NODE_OPTIONS="--max-old-space-size=4096"; npm run build

Or put it in the script itself in package.json (this form works on Mac and Linux; on Windows, prefix it with the cross-env package):

"scripts": {
  "build": "NODE_OPTIONS=--max-old-space-size=4096 next build"
}

Don't set it higher than the machine's actual memory. If the server has 2 GB of RAM and you allow a 4 GB heap, the operating system will kill the process instead — see exit code 137 below. Leave room for everything else running on the machine.

Fix 2: Reduce what the build needs

  • Run type-checking separately from bundling, or limit it to changed files.
  • Turn off production source maps if you don't need them (or generate them only in CI).
  • Update your build tools — newer versions are often much more memory-efficient (Vite 8's Rust-based bundler is one example).
  • Build on a bigger machine (in CI) and deploy the output, rather than building on a small production server.

Fix 3: Stream instead of loading everything

Scripts that read a 2 GB CSV with fs.readFileSync, or SELECT * a million rows into an array, will run out of memory. Process data in chunks — read files as streams, page through query results, or use database cursors. (API pagination covers the same idea for APIs.)

Fix 4: Find the memory leak

If a server's memory grows steadily until it crashes, raising the limit only delays the crash. Common causes:

  • Caches that never evict — a global Map storing every request's data.
  • Event listeners added repeatedly and never removed.
  • Timers (setInterval) that keep references alive.
  • Arrays that only grow, like an in-memory log.
  • Closures holding onto large objects longer than intended.

How to investigate: watch memory over time (process.memoryUsage()), take heap snapshots with Chrome DevTools (node --inspect) and compare them, and look at what's growing. Finding Node.js memory leaks walks through it in detail.

Exit code 137 is a different problem

If your process just disappears with exit code 137 or a log line like "Killed" — with no JavaScript error — that's not Node's heap limit. The operating system or container killed it for using more memory than the machine or container allows. Fix it by giving the container more memory, or by lowering the heap limit so Node stays within it. See how container CPU and memory limits work.

Don't just let your AI tool raise the limit

Asked to fix this error, AI tools often reach straight for --max-old-space-size=8192. That's right for a big build; it's wrong for a leaking server, where it hides the problem until the crash comes back bigger. Tell the tool when and where the crash happens so it can tell which case you're in.

The summary

  • The error means Node used more memory than its heap limit.
  • Builds on big projects may genuinely need more: raise it with --max-old-space-size, within the machine's real memory.
  • Reduce build memory, stream large data, and build on bigger CI machines.
  • A server whose memory grows until it crashes has a leak — find it rather than raising the limit.
  • Exit code 137 means the OS or container killed it — a different fix.

EasySpawn servers come in sizes up to 8 vCPUs and 16 GB of memory, so heavy builds have room to run — and Claude Code can watch a process's memory on the real server to tell a big build from a leak. See pricing or join the waitlist.

Related: What Is Node.js? · Debugging for Beginners · Why Does My App Work Locally but Not in Production? · Node.js vs Bun vs Deno

Keep reading