← The blog
DevOps·Dec 2025·6 min read

Fixing Next.js build heap OOM (NODE_OPTIONS deep-dive)

A build that died at 1.6 GB on a 2 GB box, traced to the default V8 heap cap and fixed without buying more RAM.

The build worked on my laptop and died on the VPS with "JavaScript heap out of memory". The box had 2 GB of RAM free, so this was not a hardware problem. It was V8 capping its old-space heap well below the memory the machine actually had, and the fix is one environment variable, applied with some care.

The default heap ceiling

Node does not use all available memory by default. The V8 old-space limit sits around 2 GB regardless of how much RAM the host has, and on smaller machines the effective ceiling is lower. A large Next.js build, especially one with many pages and heavy static analysis, walks right into it.

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

That raises the old-space cap to 4096 MB. The number is in megabytes, and it should sit below the machine's real free memory with headroom, because V8 also uses memory outside old space.

Do not set it blindly

Setting 4096 on a 2 GB box is worse than the original problem, because now the process tries to grow past physical memory and the kernel OOM-killer steps in, which is harder to diagnose than a clean V8 error. On a 2 GB box I set 1536, accept that builds are tighter, and look at reducing the build's footprint instead of pretending there is RAM that is not there.

Where to put it

The variable belongs in the build environment, not committed into next.config. In CI it goes in the pipeline env. On the VPS it lives in the deploy script next to the build command, so it applies only during the build and not to the running server, which has very different memory needs.

export NODE_OPTIONS="--max-old-space-size=3072"
npm run build
unset NODE_OPTIONS

Treat OOM as a symptom

Raising the cap is the fast fix, but a build that needs 4 GB is often telling you something. In one case the real culprit was a data file being imported into hundreds of pages and held in memory all at once. Splitting that data and loading it per-route dropped peak heap by half, and the flag became unnecessary. The variable buys you room, but it is worth asking why you needed the room before you reach for it.

The short version: the heap limit is a V8 default, not your machine's limit. Raise it to fit the host with headroom, set it only for the build step, and check whether the build's memory appetite is reasonable before you assume the answer is always more.

Next.jsNodeV8Build
Let's talk

Let's build
SOMETHING REAL.

Have a system that needs to think, scale, or just finally get shipped? Let's make it happen.

Based in Dhaka, Bangladesh · Available worldwide