Webpack "JavaScript heap out of memory" - Fix Build OOM in CI
The Node process running the build exhausted V8's heap and aborted. Large bundles, source maps, and many modules can exceed the default heap, especially on a small CI runner.
What this error means
The build dies with FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory, often after running a while. It may pass locally on a bigger machine and fail on a smaller runner.
<--- Last few GCs --->
[1234:0x...] 60123 ms: Mark-sweep 2046.8 (2050.1) -> 2046.0 MB, ...
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
1: 0xb09c10 node::Abort() ...Diagnose it: is it resolution, transform, or memory?
Bundler failures in CI fall into three families and the error text often points at the wrong one. A module that resolves on your machine and not on the runner is nearly always case sensitivity or a missing optional dependency; a transform error is a config or version mismatch; and an unexplained kill with no stack is the out-of-memory reaper, not a build error at all.
# 1. resolution: does the file exist with EXACTLY that case?
git ls-files | grep -i "the/imported/path"
# 2. transform: what versions is CI actually resolving?
npm ls webpack vite rollup esbuild typescript 2>/dev/null | head -20
# 3. memory: was it killed rather than failed?
# exit 137 = SIGKILL (OOM). Nothing in the bundler log will explain it.
node --max-old-space-size=4096 node_modules/.bin/vite buildCommon causes
Heap default too low for the build
V8's old-space cap can be lower than a big production build needs. Many modules, vendor chunks, and high-quality source maps all inflate peak memory.
Small runner / container memory limit
A constrained CI runner (or a container --memory cap) gives Node less RAM than the build peak, so it OOMs where a developer laptop would not.
How to fix it
Raise Node's heap limit
Give V8 more old-space via NODE_OPTIONS so the build fits.
export NODE_OPTIONS=--max-old-space-size=4096
npm run build
# package.json: "build": "node --max-old-space-size=4096 ./node_modules/.bin/webpack"Shrink the build's memory footprint
- Use cheaper source maps in CI (e.g.
source-maponly where needed) or disable them for the failing step. - Split vendor code and lazy-load routes so fewer modules are in memory at once.
- Use a bigger runner for the build job if the project is genuinely large.
Make the build reproducible before you debug it
- Pin the Node major in
setup-nodeand inengines. A bundler that resolves native bindings will pick a different prebuilt binary across majors. - Delete
node_moduleslocally and reinstall from the lockfile before concluding the runner is at fault; most "works locally" reports are stale local state. - Set
CI=truelocally to reproduce. Several toolchains change behaviour under it, including treating warnings as errors. - Exit code 137 is an out-of-memory kill. Raise
--max-old-space-sizeor move to a larger runner rather than searching the bundler config.
How to prevent it
- Set a sensible
--max-old-space-sizefor the build job in CI. - Right-size the build runner to the project's real peak memory.
- Keep bundles lean with code-splitting and modest source-map settings.