How much RAM does Next.js need on a VPS?
Size a Next.js VPS by separating build, idle and load memory. Learn how to measure the application and budget for the whole server.
Memory rises, the site slows down and the process restarts. Before raising the heap limit, establish what grew and when. The cause could be the build, a cache, large responses or objects that remain reachable.
This guide follows a reproducible investigation. High usage alone does not establish a leak, and server measurements need to stay separate from browser-tab memory.
Record Node and Next.js versions, the startup command and container or service limits. A next dev process keeps compilation tools that do not describe next start. A failure during next build is another case again.
Read the log before the restart. A V8 heap error and a process killed by the system’s memory limit are different signals. Keep the timestamp, PID and workload. A VPS-wide chart alone cannot attribute memory to Next.js.
node --version
npm ls next react react-dom
ps -eo pid,ppid,rss,comm --sort=-rssprocess.memoryUsage() reports values including rss, heapUsed, heapTotal, external and arrayBuffers in bytes. Call it inside the application process you are investigating, for example through private instrumentation. Running node -e alongside it would measure only that new process.
If heapUsed falls after collection while RSS remains high, that does not establish a JavaScript leak. Native allocations, buffers and allocator behavior deserve investigation too. For multiple processes, also observe the whole service group. Keep diagnostic endpoints private.
const timer = setInterval(() => {
const { rss, heapUsed, external } = process.memoryUsage();
console.log(JSON.stringify({
event: "memory-sample",
pid: process.pid,
rss, heapUsed, external,
at: new Date().toISOString()
}));
}, 10000);
timer.unref();Choose a suspicious route, repeat an identical batch of requests and let the server settle afterwards. Record values after each batch. An initial rise that reaches a plateau can reflect module loading or a bounded cache.
Persistent growth after comparable batches needs closer investigation. Examine per-user global collections, caches without expiry, subscriptions that remain active and large objects retained by closures. Include cancelled requests and interrupted connections if the application streams responses.
If the build fails, identify the stage: transformation, TypeScript checking or prerendering. Generating a page for thousands of parameters differs from loading a large compiler dependency.
Next.js documents an experimental build-memory diagnostic mode, with restrictions depending on the worker and build engine. Check applicability to your version before using it. Reduce an import or generation batch on a branch and compare the result. Increasing --max-old-space-size does not create RAM and can move the process closer to the VPS limit.
A heap snapshot lets you inspect objects and their retaining paths. Compare captures taken at equivalent points in a scenario, then investigate what remains after later batches. The reference preventing release matters more than object size alone.
Capturing can pause the process and require substantial additional memory. Use a diagnostic instance with suitable data. Snapshots can contain sensitive application information, so keep them private. Do not expose the debugging port publicly.
After the fix, repeat the scenario, cancellations and idle interval. Compare memory, errors and response times. Lower heap usage alongside a throughput collapse can reflect a collection tradeoff rather than an overall improvement.
To evaluate another runtime such as PRNext, retain the method and routes. Switching runtimes does not automatically fix an unbounded application cache. Verify compatibility first, then measure the entire service.