Control Node.js Heap Size with ENV in Kubernetes – New --max-heap-size in 25.9.0
Node.js 25.9.0 adds support for the --max‑heap‑size flag in the NODE_OPTIONS whitelist, allowing containers on Kubernetes to set heap limits via environment variables, reducing OOM kills, while also introducing experimental stream/iter API, test‑module mock changes, new Web Crypto algorithms, and other enhancements.
--max-heap-size now allowed in NODE_OPTIONS
When a Node.js service runs inside a Kubernetes pod, the pod may have a memory limit (e.g., 1 GB) that the Node.js process does not see. The process will keep expanding its V8 heap until it hits the cgroup hard limit, causing the kernel to kill it with an OOMKilled event and no logs.
The usual workaround is to add the --max-old-space-size flag, but that only limits the V8 old generation, not the entire heap. The --max-heap-size flag has existed for a long time, yet it could only be set on the command line and could not be passed through the NODE_OPTIONS environment variable.
Node.js 25.9.0 removes this restriction: --max-heap-size is now on the NODE_OPTIONS whitelist, so it can be supplied via an environment variable.
# Previously you had to modify the start command
node --max-heap-size=750 app.js
# Now you can set it through NODE_OPTIONS
NODE_OPTIONS='--max-heap-size=750' node app.jsThis means you can inject the heap‑size limit directly in a pod spec without touching the Dockerfile or start script. Combined with Kubernetes’ Downward API, the value can be computed dynamically from the pod’s actual memory limit, simplifying management across many services.
Why set this value instead of relying solely on the pod memory limit? The pod limit is a hard OS constraint: exceeding it results in an immediate kill with no diagnostic information. In contrast, --max-heap-size is a soft limit enforced by Node.js; exceeding it throws a JavaScript “heap out of memory” error, giving the process a chance to log, report metrics, trigger alerts, and exit gracefully. A common practice is to set --max-heap-size to roughly 75 % of the pod’s memory limit, leaving room for buffers, native extensions, and non‑V8 memory overhead.
Experimental stream/iter API
The release also introduces stream/iter, an experimental API authored by James Snell that provides iterator‑based primitives for stream processing, aiming to make the notoriously complex Node.js Stream API easier to use. The API is still marked experimental and may change; it is not recommended for production yet.
import { … } from 'stream/iter';Test module mock API adjustment
The built‑in test runner’s mock module options have been consolidated. Previously MockModuleOptions had two fields, defaultExport and namedExports. In 25.9.0 they are merged into a single exports field.
// Old usage
t.mock.module('./foo', {
defaultExport: myDefault,
namedExports: { bar: myBar }
});
// New usage
t.mock.module('./foo', {
exports: {
default: myDefault,
bar: myBar
}
});An automatic migration tool is provided; running npx codemod @nodejs/mock-module-exports rewrites the code. The change aligns Node.js’ mock API with other mainstream testing frameworks and reduces migration friction.
Web Crypto API adds two algorithms
Node.js now supports the TurboSHAKE and KangarooTwelve algorithms from the Web Cryptography standard, contributed by Filip Skokan. These SHA‑3 variants offer better throughput than standard SHA‑3 and are useful when matching browser Web Crypto behavior, though most business code will not need them immediately.
Other noteworthy changes
SEA (single‑executable) now supports ESM code caching, improving startup speed for bundled applications. AsyncLocalStorage gains support for the using syntax, aligning with the TC39 explicit resource management proposal. The fs.cpSync function fixes handling of non‑ASCII paths on Windows. Dependency updates include npm 11.12.1, SQLite 3.51.3, and the tz database to 2026a.
Conclusion
Version 25.9.0 is not a major release, but adding --max-heap-size to the NODE_OPTIONS whitelist is a tangible improvement for teams deploying Node.js in containers, eliminating a cumbersome workaround. The experimental stream/iter and the new using syntax for AsyncLocalStorage demonstrate ongoing API modernization. Since 25.x is a Current line, production environments should wait for the LTS transition unless they are prepared to handle the breaking change in the mock API.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
