The engines field in package.json states which Node.js and npm versions a package works with, but npm treats it as advice. Unless the engine-strict setting is on, a mismatch only produces a warning when the package is installed as a dependency. If you need a hard rule, enforce it yourself.
What the field says
{
"engines": {
"node": ">=20",
"npm": "~10.0.0"
}
}
The npm documentation says that if you omit the version or set it to a star, any Node version is accepted. It also says that unless the user sets the engine-strict config flag, the field is advisory only and will only produce warnings when the package is installed as a dependency.
Why this is a dependency hygiene issue
Your dependencies run on a runtime, and the runtime is itself a dependency. If developers use three Node versions, CI uses a fourth and production a fifth, you cannot reason about which fixes apply or why a bug appears in one place only.
Runtime versions matter for security too: end of life runtimes stop getting fixes. This post does not cover the support schedules, so check your runtime's official release page for current dates.
Making it strict
- Set engine-strict in a committed project config file so that everyone installing the project gets the same rule. The npm ci documentation makes a related point: settings that affect installs should live in the project .npmrc and be committed.
- Pin the runtime where it is used. Use a version file or a container image tag for your build, and a digest where you can, as in container image digests vs tags.
- Make CI print the runtime and package manager versions at the start of a build. A mismatch becomes obvious.
- Have CI fail if the runtime is not in the allowed range, instead of relying on the warning.
For libraries you publish
The field helps consumers learn your tested range. Be honest in it. A claim of support for versions you never test is worse than a narrow range. Remember that consumers see only a warning by default.
For applications
Treat the engines field as documentation of your intent and enforce it in the build image. The field is the statement and the image is the control.
A short checklist
- Is a runtime version declared in the repository?
- Does the CI image match it?
- Does production match it?
- Is engine-strict set where you need it to be a hard failure?
- Is there a date to review the runtime version?
Safeguard's SBOM and dependency scanning covers your packages, and a free scan is at gold.safeguard.sh/scan.
Quick check
Does engines block an install on the wrong Node version?
Not by default. It only warns unless engine-strict is set.
Where should I enforce my runtime version?
In the build image and CI, since the field itself is advisory.
Sources
Last reviewed: 19 October 2026.