ERR_WORKER_OUT_OF_MEMORY

Fix 'JavaScript heap out of memory' (ERR_WORKER_OUT_OF_MEMORY) on npm build

Node's default heap is too small for your build. Raise the limit, kill memory leaks, or upgrade your hardware. Here's how.

Quick answer: Set NODE_OPTIONS=--max-old-space-size=4096 before running npm build, or add it to the build script. That raises Node's heap ceiling from its default (often 2GB) to 4GB. If it still dies, you've got a memory leak or a hardware wall.

I know this error is infuriating. You're mid-deploy, the terminal spits out a wall of garbage ending in FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory, and npm exits with a code your CI pipeline treats like a heart attack. The specific trigger for ERR_WORKER_OUT_OF_MEMORY is usually a build tool like Webpack or Vite spawning worker threads that each try to allocate more memory than Node's default heap allows.

Here's the thing most people miss: Node's heap limit isn't a hard OS limit. It's a V8 setting. On a machine with 32GB of RAM, Node still acts like it's on a 2GB machine until you tell it otherwise. That default was chosen years ago when 2GB was a lot. Now every project ships with a 500MB node_modules and a source map config that eats memory like popcorn. The error isn't your code failing—it's Node being polite about resource usage in the worst possible way.

Fix 1: Raise the heap limit (the one you'll actually use)

This works 80% of the time. Run your build with a bigger ceiling.

On macOS or Linux:

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

On Windows (cmd):

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

On Windows (PowerShell):

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

4096 means 4GB. If your machine has 16GB or more, bump it to 8192 (8GB). Don't go higher than half your physical RAM—Node will happily try to use it and then your OS starts swapping, which is slower than just allocating more upfront.

The permanent fix is to put this in your package.json build script so you don't have to remember flags every time:

"scripts": {
  "build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 webpack --mode production"
}

Use cross-env if your team runs a mix of Windows and Unix machines. Yes, it's an extra dependency. No, you don't want to maintain two scripts.

Fix 2: Find the actual memory hog

If 8GB still isn't enough, you're not fixing the error—you're postponing it. Something in your build is retaining memory it shouldn't. The usual suspects:

  • Source maps. Generating full source maps for a 2MB bundle can triple memory use. Try devtool: 'source-map' → 'cheap-source-map' in production. You lose some debugging fidelity. You gain a build that finishes.
  • Babel transforming node_modules. If your babel-loader config doesn't have exclude: /node_modules/, it's compiling every dependency from scratch. Add that exclusion.
  • Circular imports. Rare, but a circular dependency chain across 50+ modules can cause Webpack's module graph to balloon. Run npx madge --circular src/ to check.
  • Worker threads piling up. ERR_WORKER_OUT_OF_MEMORY specifically means a worker process hit its limit. Tools like Terser or thread-loader spin up one worker per CPU core by default. On a 16-core CI runner, that's 16 heaps each trying to hold data. Cap it: new TerserPlugin({ parallel: 4 }).

Fix 3: Split the build

If you're building a monorepo or a huge app, one giant build process is the problem. Break it up:

npm run build:client
npm run build:server
npm run build:workers

Each gets its own Node process with its own fresh heap. It's slower overall, but it finishes. I've seen teams drop build failures from daily to zero this way.

Alternative fixes if none of that works

Check your Node version

Node 16 and earlier had worse garbage collection for large heaps. If you're still on Node 16, upgrade to Node 20 LTS or 22. Run node --version. This alone has fixed it for people I've helped.

Disable the worker entirely

Some build tools let you opt out of worker threads. For Webpack, parallel: false in the optimization config. You lose build speed, but the memory ceiling problem goes away because everything stays in the main process.

Swap the build tool

If you're on an old Webpack 4 setup and can migrate to Vite or esbuild, do it. Vite's production build uses Rollup, which is dramatically more memory-efficient. This is a big change though—don't do it the day before a release.

Throw hardware at it

Your CI runner probably has 4GB of RAM. That's not enough for a modern JS build anymore. Bump the runner to 8GB or 16GB. This isn't a code fix, but sometimes it's the honest one.

Prevention: stop it from coming back

Put the NODE_OPTIONS setting in a .env file at your project root and load it in CI. Set a memory budget in your build tooling—Webpack has performance.maxAssetSize and maxEntrypointSize warnings that catch bloat before it becomes a crash. And check your bundle size on every PR with a tool like bundlewatch or size-limit.

The real fix is treating build memory like any other resource: measure it, cap it, and alert when it grows. The heap limit flag gets you unblocked today. The prevention work keeps you from Googling this error again in six months.

Related Errors in Programming & Dev Tools
0X80000002 Fix EXCEPTION (0X80000002) in Visual Studio: Step by Step Unknown host 'd29vzk4ow07wi7.cloudfront.net' Android Studio Gradle Sync: Unknown Host d29vzk4ow07wi7.cloudfront.net 0X000002FE ERROR_DBG_EXCEPTION_HANDLED 0X000002FE: Debugger swallowed it 0XC0000091 Floating-point overflow (0xC0000091) — real fixes that work

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.