Node.js
The runtime under most of this stack, and the parts of it that bite in production.
Node.js is the runtime under most of what CodeNx covers — build tooling, application servers, the scripts that glue deployments together. Its production behaviour is worth knowing separately from whatever framework sits on top.
Reach for Node when the ecosystem is the reason: a library that only exists in npm, a team that already writes TypeScript, tooling that assumes it. Reach for something else when the workload is CPU-bound, because a single-threaded event loop is the wrong shape for that and worker threads only partly help.
Version policy first. Run the active LTS line — even-numbered majors, thirty months of support. Odd-numbered releases are explicitly not for production. Pin the minor version in the Dockerfile, because “node:22” resolves to something different every few weeks and a rebuild should not change your runtime.
Recent releases have absorbed a surprising amount of what used to be
dependencies: a test runner, a watch mode, .env file loading, a fetch
implementation. Checking whether the platform already does something is worth
doing before adding a package for it.
The production behaviour that catches people is process lifecycle. Node does not handle SIGTERM for you, so a container being replaced kills the process mid-request unless you close the server yourself. Unhandled promise rejections terminate the process by default, which is correct but needs a supervisor and a useful log line. And the runtime cannot see a container memory limit, so heap size has to be bounded explicitly or the OOM killer does it for you.
CodeNx does not have standalone Node.js articles yet. This hub maps the topic and links the primary sources until it does.
Common problems
Failure modes that come up repeatedly with Node.js, and where each one is solved.
- The process ignores SIGTERM and gets killed
- Without an explicit handler the server keeps accepting connections until the runtime kills it, which drops in-flight requests on every deploy.
- An unhandled promise rejection takes the process down
- Since Node 15 this exits by default. That is usually correct, but it needs a supervisor that restarts and a log line that says which promise.
- Memory grows until the container is OOM-killed
- Often a container memory limit the runtime cannot see. Set `--max-old-space-size` below the container limit so the heap is bounded.
Frequently asked questions
Which Node version should a production service run?
The active LTS line. Even-numbered majors get thirty months of support; odd-numbered ones are not intended for production at all. Pin the minor in your Dockerfile so a rebuild does not silently change the runtime.
Do I still need a process manager in a container?
No. The container runtime restarts the container, which is the same job. Run the application as PID 1 with an init process for signal forwarding if the base image does not provide one.
How do you shut a Node server down cleanly?
Handle SIGTERM, stop accepting new connections with `server.close()`, let in-flight requests finish, then exit. Without it, every rolling deploy drops whatever was in progress.
Sources
- Node.js API documentation OpenJS Foundation Primary source
- Node.js release schedule OpenJS Foundation Primary source