If you are running a large production build or a data-heavy script in Node.js, you have probably run into this crash:
Plaintext
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
The V8 stack trace that follows usually doesn't show the actual file or line causing the issue, making it difficult to debug.
Here is why this happens and how to fix it across your local environment, build scripts, and CI/CD pipelines.
Why This Happens
By default, the V8 engine limits the memory a single Node.js process can allocate. Depending on your Node version and system architecture, this limit defaults to roughly 1.5 GB or 4 GB.
This is usually fine for standard applications, but modern build tools (like Webpack, Vite, Next.js, or the TypeScript compiler) build large abstract syntax trees (AST) in memory. If your dependency graph or codebase grows past a certain size, the bundler hits the default allocation limit and crashes.
The Fix: Increase max-old-space-size
The direct solution is to instruct the V8 engine to allocate more memory using the --max-old-space-size flag (defined in megabytes).
Common allocation values
-
4GB Allocation:
--max-old-space-size=4096 -
8GB Allocation:
--max-old-space-size=8192
1. Temporary Local Environment Fix
To unblock your local machine for a single run, set the environment variable before your build command:
Bash
# Unix/macOS
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
2. Permanent Project Fix (package.json)
To ensure everyone on the team uses the same config, add it directly to your build scripts inside package.json. Use cross-env to avoid platform-specific syntax issues on Windows:
JSON
{
"scripts": {
"build": "cross-env NODE_OPTIONS='--max-old-space-size=4096' next build",
"compile": "cross-env NODE_OPTIONS='--max-old-space-size=4096' vite build"
}
}
Fixing the Error in CI/CD Pipelines
If your local builds pass but your deployment servers crash, you need to pass the memory variable to your runner or cloud provider.
GitHub Actions
Add the environment variable to your build step configuration:
YAML
- name: Run Production Build
env:
NODE_OPTIONS: --max-old-space-size=4096
run: npm run build
Docker Containers
Pass it as an environment parameter within your Dockerfile:
Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY . .
ENV NODE_OPTIONS="--max-old-space-size=4096"
RUN npm run build
Managed Hosting (Vercel, Netlify, Cloudflare Pages)
- Go to your project settings dashboard.
- Open the Environment Variables tab.
- Add a new key:
NODE_OPTIONSwith the value--max-old-space-size=4096. - Trigger a new deployment.
Checking for Underlying Problems
If you allocate 8GB or more of RAM and the build still fails, you are likely dealing with a memory leak or an infinite compilation loop rather than just a large codebase. Check these three areas:
Disable Source Maps in Production
Generating source maps for massive third-party dependencies takes a lot of memory. If your server is constrained, disable them in your config file to see if memory usage drops.
JavaScript
// next.config.js example
module.exports = {
productionBrowserSourceMaps: false,
};
Audit Circular Dependencies
Circular imports force compilers into recursive evaluation loops that drain memory. Use madge to audit your source directory for cyclical references:
Bash
npx madge --circular ./src
Inspect the Runtime Heap
If the crash occurs on a running backend server rather than during a build script, you have a runtime leak (e.g., event listeners not being cleaned up, or global cache arrays growing indefinitely).
Start your server with the inspector flag enabled:
Bash
node --inspect index.js
Open Chrome DevTools (chrome://inspect), target your Node process, and take a Heap Snapshot to see which objects are failing to garbage collect.
Top comments (0)