How to Increase Node.js Memory Limit (Heap Size Guide)
Fix 'JavaScript heap out of memory' errors by raising Node's V8 heap with --max-old-space-size, NODE_OPTIONS, npm scripts, PM2, and Docker.
How to Increase the Node.js Memory Limit
If a Node build or script dies with FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory, V8 has hit its old-generation ceiling. On 64-bit builds of modern Node.js the default is roughly 4 GB (historically much lower - 1.4 GB on 64-bit and only about 700 MB on 32-bit before Node 12). Large webpack/Next.js bundles, TypeScript project references, Jest suites, and streaming CSV/ETL jobs blow past this quickly. This guide shows every practical way to raise it.
1. Understand the flag
V8 exposes two knobs Node.js forwards to it:
--max-old-space-size=<MB>- the old generation, where long-lived objects live. This is the flag you almost always want.--max-semi-space-size=<MB>- the young generation (each of the two semi-spaces). Bumping to 64 or 128 can reduce minor GC pauses in allocation-heavy workloads, but do not raise it wildly - young GC gets slower.
Values are in megabytes. Leave ~1 GB of RAM for the OS and any sibling processes.
2. Set it on the command line
node --max-old-space-size=8192 ./scripts/import-data.js
node --max-old-space-size=8192 --max-semi-space-size=128 server.js
Flags must appear before the script path or they will be passed to your script as arguments.
3. Use NODE_OPTIONS for child processes
npm, pnpm, webpack, Next.js, Vite, and Jest all spawn Node with their own argv. The reliable way to reach those children is the NODE_OPTIONS environment variable:
# macOS / Linux
export NODE_OPTIONS="--max-old-space-size=8192"
npm run build
# Windows PowerShell
$env:NODE_OPTIONS="--max-old-space-size=8192"
npm run build
# Windows cmd.exe
set NODE_OPTIONS=--max-old-space-size=8192 && npm run build
4. Bake it into package.json (cross-platform)
Hardcoding NODE_OPTIONS=... in front of a script breaks on Windows. Use cross-env:
{
"scripts": {
"build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 next build",
"test": "cross-env NODE_OPTIONS=--max-old-space-size=6144 jest --runInBand"
}
}
Install once: npm install --save-dev cross-env.
5. Verify the new limit
Do not assume - measure. Add a quick log at boot:
const v8 = require('node:v8');
const mb = (b) => (b / 1024 / 1024).toFixed(0) + ' MB';
console.log('heap limit:', mb(v8.getHeapStatistics().heap_size_limit));
console.log('rss:', mb(process.memoryUsage().rss));
heap_size_limit should be close to the value you passed. process.memoryUsage() also returns heapUsed, heapTotal, and external - graph those over time to spot real leaks instead of just raising the ceiling forever.
6. PM2, systemd, and Docker
PM2 - use node_args in ecosystem.config.js:
module.exports = {
apps: [{
name: 'api',
script: 'dist/server.js',
node_args: '--max-old-space-size=4096',
max_memory_restart: '3500M'
}]
};
max_memory_restart should sit below the heap cap so PM2 restarts the process before V8 aborts.
systemd - set it in the unit file:
[Service]
Environment=NODE_OPTIONS=--max-old-space-size=4096
ExecStart=/usr/bin/node /srv/app/server.js
Docker - export it in the Dockerfile or compose file, and remember to give the container enough RAM:
ENV NODE_OPTIONS="--max-old-space-size=3072"
# docker run --memory=4g ...
If you set --max-old-space-size=8192 but the container is capped at 2 GB, the Linux OOM killer will terminate Node before V8 ever hits its own limit.
7. When raising the heap is the wrong fix
- Real leaks: if
heapUsedgrows monotonically, take a heap snapshot with--inspectornode --heapsnapshot-signal=SIGUSR2and diff it. - Loading huge files at once: switch to
fs.createReadStreamand process line-by-line rather thanfs.readFileSync. - ts-loader / babel on monorepos: enable
transpileOnlyor move to SWC/esbuild before raising RAM.
Raise the limit to unblock today's build, then fix the allocation pattern so you can lower it back down tomorrow.