Skip to content

Node.js errorFATAL ERROR: “Reached heap limit Allocation failed: JavaScript heap out of memory”

A build (next build, vite build, webpack, tsc, jest) or a running Node.js server stops with FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory. Node.js used all the memory V8 allows for its heap. For a build, the limit is often just too low for the project. For a server that dies after hours, it is usually a leak.

Short answer

For a one-off build, raise the limit with NODE_OPTIONS=--max-old-space-size=4096 (in MiB), and keep it below the machine’s or container’s memory. In CI and Docker, check the runner really has that much RAM. For a server that grows until it crashes, raising the limit only delays the crash: take heap snapshots and look for caches, arrays or listeners that only grow. Also stop loading whole files or query results into memory at once: stream or page them.

Why the heap ran out, and the fix

  1. 01

    The build needs more memory than the default

    “Sets the max memory size of V8's old memory section.” Node.js, Command-line options: --max-old-space-size

    Big TypeScript projects, source maps and bundlers can need more heap than Node.js picks by default. Raise the old-space limit for that command, set in MiB.

    # one command
    NODE_OPTIONS=--max-old-space-size=4096 npm run build
    
    # package.json (use cross-env on Windows)
    "build": "NODE_OPTIONS=--max-old-space-size=4096 next build"
  2. 02

    The limit is higher than the machine has

    “On a machine with 2 GiB of memory, consider setting this to 1536 (1.5 GiB) to leave some memory for other uses and avoid swapping.” Node.js, Command-line options: --max-old-space-size

    Setting 8192 on a 4 GB CI runner or container swaps or gets killed by the system (exit code 137) instead. Leave room for the operating system and other processes, and pick a larger runner if the build really needs more.

  3. 03

    A memory leak in a long-running server

    If memory climbs steadily until the process dies, something keeps references: an in-memory cache without a limit, a growing array or Map, event listeners added per request, or timers never cleared. Take two heap snapshots a few minutes apart and compare what grew. Take them well before the limit, because a snapshot of a nearly full heap can run out of memory itself.

    node --inspect=127.0.0.1:9229 server.js   # never expose the inspector publicly
    # open chrome://inspect, Memory tab, take a heap snapshot,
    # send traffic, take another, select it and switch the view to Comparison
  4. 04

    Loading everything at once

    Reading a large file with readFileSync, building one huge array from a database query, or JSON.stringify on a large object all need the whole thing in memory. Stream files and page through queries.

    import { createReadStream } from 'node:fs';
    import readline from 'node:readline';
    const lines = readline.createInterface({ input: createReadStream('big.csv') });
    for await (const line of lines) handle(line);

Checked against the vendor’s docs on : Node.js: Command-line options (--max-old-space-size).

Rather hand it over?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

Related: Firebase Functions memory limit exceeded · Node.js ECONNRESET (“socket hang up”) · Node.js “Cannot find module”

Questions

More on this error

What number should I use for --max-old-space-size?

Enough for the job and well below the machine’s memory: 4096 is common for large builds on an 8 GB machine. If a build needs much more, look at what it is doing, such as source maps or type checking, before raising it further.

Exit code 137 with no heap error: is it the same problem?

Related but different. A V8 heap error aborts the process itself (exit code 134 on Linux). Exit 137 means the operating system or container killed the process for using too much memory, often because the Node.js limit is set higher than the container allows.

Can you fix it for me?

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

A different error?

Describe it and get a written quote

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.