To update Node version safely, choose the target Node release, update your local runtime with a version manager or installer, pin the same version in your project with .nvmrc, package.json, Docker, or your hosting settings, reinstall dependencies when needed, then run the production build before deploying. The real work is not clicking “download.” It is making sure every place that builds the app uses the same Node.js version.
That is where teams usually get burned. The app works on one laptop, fails in CI, then deploy logs start throwing errors about optional dependencies, unsupported engines, or a package lock written by a different npm version. Your JavaScript app did not become haunted. It just has three runtimes pretending to be one.
Table of contents
- The safe way to update Node version
- First, check the Node version you already use
- Pick the right target version
- Update Node on macOS, Linux, and Windows
- Pin Node inside the project
- Update Node for CI, Docker, and production hosting
- What to test before deploying
- Common upgrade failures and fixes
- FAQ
The safe way to update Node version
Most search results for update node version show installation commands first. That is useful, but incomplete. Updating the binary is the easy part. Keeping your build reproducible is the part that decides whether the deploy ships.
Use this sequence:
- Check the current Node and npm versions.
- Choose a target release, usually active LTS unless a framework requires newer.
- Update Node locally.
- Pin the version in the repository.
- Update CI and Docker images to match.
- Reinstall dependencies if the npm or native-module boundary changed.
- Run tests and the same production build command your host will run.
- Deploy and read the build logs.
If you host Node services on RunxBuild, keep the project version visible in your repo and deployment settings. The Node service docs are the place to line up build commands, start commands, environment variables, and deploy behavior. If the upgrade changes the size of your instance or memory needs, use the RunxBuild hosting calculator before guessing your monthly cost.
First, check the Node version you already use
Before changing anything, get the current state out of your head and into the terminal.
node -v
npm -v
which node
which npm
On Windows PowerShell, use:
node -v
npm -v
where node
where npm
Then check the project itself:
cat .nvmrc 2>/dev/null
cat package.json | grep -A 5 '"engines"'
You are looking for a mismatch between “what my shell runs” and “what the app expects.” A common example is a project that says Node 20 in .nvmrc, while CI still runs Node 18. Another is a Dockerfile that starts with node:16-alpine because nobody has looked at it since the first prototype shipped.
If the project has no pinned Node version, add one during the upgrade. A deployment platform should not have to guess which runtime your app wants.
Pick the right target version
For most production apps, use the current active LTS version of Node.js unless your framework, dependency tree, or security policy says otherwise. LTS releases are the calm path: fewer surprises, wider package support, and better compatibility with build tooling.
Use the official Node.js download page and Node.js release schedule to confirm the release line. Do not upgrade to a “Current” release just because the number is larger. Production infrastructure is not a scoreboard.
A practical decision table:
| Situation | Good target |
|---|---|
| New production app | Active LTS |
| Existing app on old LTS | Next active LTS after tests pass |
| Framework requires newer Node | Minimum version recommended by the framework |
| Security patch required | Latest patch in your current major version first |
| Native modules or old dependencies | Upgrade one major version at a time |
If you are jumping multiple major versions, read framework release notes. A Node upgrade can change OpenSSL behavior, ESM/CJS edges, native module builds, npm lockfile behavior, and package engine checks.
Update Node on macOS, Linux, and Windows
There are several correct ways to update Node.js. The best one depends on how your team manages development machines.
Option 1: Use nvm on macOS or Linux
nvm is popular because it lets each project use its own runtime. That matters when one repo needs Node 18 and another needs Node 22.
nvm install 22
nvm use 22
node -v
npm -v
To make the version automatic for the project:
echo "22" > .nvmrc
nvm use
Some teams prefer a full version such as 22.13.1 instead of 22. Either can work. A full version gives tighter reproducibility; a major version lets developers receive patch updates more naturally.
Option 2: Use fnm, Volta, or asdf
If your team already uses another version manager, keep using it. The important thing is not the logo on the version manager. The important thing is that node -v becomes predictable inside the repo.
For example, with Volta:
volta install node@22
volta pin node@22
Volta writes the runtime into package.json, which is useful for teams that want the version tracked next to scripts and dependencies.
Option 3: Use the official installer
The official installer is fine for a single machine, especially on Windows. Download the LTS installer, run it, then restart the terminal and verify:
node -v
npm -v
The risk is team drift. If five developers install Node manually and nobody pins the project version, you have five slightly different build environments. That works until it does not, usually at the worst possible time.
Option 4: Update through a package manager
Package managers like Homebrew, apt, winget, and Chocolatey can install Node. They are convenient, but they may lag behind official releases or install a version different from the one your project expects.
Use them when your environment standardizes on them. Avoid mixing package-manager Node with nvm-managed Node on the same shell path unless you enjoy debugging which node like it is a murder mystery.
Pin Node inside the project
A Node version update is not complete until the repository tells future builders what to use.
The most common options are .nvmrc, package.json engines, Docker base images, and CI setup steps. Use more than one when it helps.
Add .nvmrc
echo "22" > .nvmrc
This helps developers running nvm use, and many platforms can read it during build setup.
Add engines to package.json
{
"engines": {
"node": ">=22 <23"
}
}
This communicates compatibility to humans, package managers, and some hosting platforms. If you need exact reproducibility, use a narrower range. If you maintain a package or app used in several environments, a range may be healthier.
Keep package lock files intentional
After changing Node or npm versions, run:
npm install
npm run build
If package-lock.json changes, review it. Do not blindly commit a huge lockfile rewrite unless the npm version change actually requires it. Lockfiles are deployment infrastructure wearing a JSON costume.
Update Node for CI, Docker, and production hosting
This is the section many “how to update Node.js” guides underplay. Your local Node version does not matter if the deployment build still runs the old one.
CI with GitHub Actions
If your app uses GitHub Actions, update actions/setup-node:
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
Using node-version-file keeps CI attached to the repo version. You can also use node-version: 22, but then you have another place to update next time.
Docker deployments
If you build with Docker, update the base image:
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
Use a versioned tag. node:latest feels convenient until it changes under you. Production builds should be boring in the best possible way.
RunxBuild services
For hosted Node services, keep the runtime version aligned with your repo, then verify the build and start commands in the dashboard. The RunxBuild services overview explains the shape of service deployments, while the GitHub setup guide covers repository-driven deploys.
A solid Node service deployment has:
- a pinned runtime version
- a repeatable install command, usually
npm ci - a build command, if the app compiles assets or TypeScript
- a start command, such as
npm startornode server.js - environment variables set outside the repo
- deploy logs visible enough to debug failures
If you are moving from a static frontend into a Node API, keep the frontend and service deployments explicit. A fast static site and a backend service can live side by side without turning the whole project into a pile of glue scripts.
What to test before deploying
The minimum test is not “the dev server starts.” Dev servers are forgiving. Production builds are less romantic.
Run:
npm ci
npm run build
npm test --if-present
npm run lint --if-present
Then, if your app has a server:
npm start
Check the routes that matter: homepage, login, API health endpoint, background job trigger, and any page that imports native dependencies. If your app uses Prisma, sharp, bcrypt, sqlite, canvas, Playwright, or other native-adjacent packages, pay extra attention after a Node major upgrade.
Useful things to inspect in deploy logs:
EBADENGINEwarnings- npm lockfile version changes
- native module compile failures
- OpenSSL-related errors
- missing environment variables
- port binding issues
- memory spikes during build
A prototype without logs is just a mystery with a URL. Keep the logs close during the upgrade.
Common upgrade failures and fixes
“npm does not support Node.js version”
Your npm version and Node version are out of sync. Install a supported Node release, or update npm with the version bundled for that Node line. The safest path is usually reinstalling the chosen Node version through your version manager.
“The engine node is incompatible with this module”
A package declares a Node version range and your runtime falls outside it. Either choose a compatible Node version or upgrade the package. Do not ignore engine errors in production unless you have tested the exact combination.
Native modules fail during install
Delete node_modules, reinstall, and make sure your build image has the required system dependencies. If the app builds in Docker, native modules compile inside the container, not on your laptop.
rm -rf node_modules
npm ci
The app deploys but crashes on start
Check the start command and the port binding. Most hosts inject a PORT environment variable. Your Node server should listen on it:
const port = process.env.PORT || 3000;
app.listen(port, "0.0.0.0");
If the app listens only on localhost or a hardcoded port, the platform may not be able to route traffic correctly.
CI passes but hosting fails
Compare the Node version, npm version, install command, build command, and environment variables. CI and hosting often drift because they are configured in different places. The fix is to move as much version truth as possible into the repository.
A better upgrade habit
The best Node upgrades are small, visible, and boring. Pin the version. Build locally. Build in CI. Deploy once. Watch logs. Roll forward with confidence.
If you are planning a bigger runtime move alongside an infrastructure change, estimate the whole app shape before it lands in production. A Node service, static frontend, database, storage, and background worker all have different cost profiles. The RunxBuild calculator is useful because it treats deployment as a system, not a single monthly sticker price.
Update the runtime, keep the deploy path repeatable, and do not let your package manager become the person making architecture decisions.
FAQ
What is the best way to update Node version?
The safest way is to use a version manager such as nvm, fnm, Volta, or asdf, then pin the chosen version in the repository. After updating, run a clean install and production build before deploying.
How do I check my current Node.js version?
Run node -v in your terminal. Also run npm -v and inspect .nvmrc, package.json engines, CI config, and Dockerfiles so you know which version every environment expects.
Should I use the latest Node version or LTS?
Most production apps should use active LTS. Use the latest current release only when you intentionally need new runtime features and have tested your framework, dependencies, CI, and deployment environment against it.
How do I update Node version in package.json?
Add or update the engines field, for example: "engines": { "node": ">=22 <23" }. This does not install Node by itself, but it tells developers, CI, and some hosting platforms which runtime the project supports.
Do I need to reinstall node_modules after updating Node?
Often, yes. If the project has native dependencies or you changed npm major versions, delete node_modules and run npm ci or npm install again. This avoids binaries compiled for the old runtime.
Why does my app work locally but fail after a Node upgrade in production?
Usually because local development, CI, Docker, and hosting are not using the same Node version or install command. Compare node -v, npm -v, lockfile changes, build logs, environment variables, and the start command.