Safeguard
Developer Tools•

devEngines or engines: which enforces your Node version?

engines is advisory for consumers, while devEngines can fail install, ci and run for contributors. What each field checks and how to set onFail.

Safeguard Security Team
4 min read

devEngines is the one that enforces tooling for the people working on your code. The npm docs say it checks the environment before install, ci and run, and fails by default. engines is advisory unless engine-strict is set, and it mostly speaks to people who install your package as a dependency.

What the npm docs say

engines declares which Node.js and npm versions a package works with. Unless the user sets engine-strict, the field is advisory: npm prints warnings when the package is installed as a dependency. Omitting a version or using "*" accepts any version. The config reference describes engine-strict (default false) as making npm refuse to install packages that declare incompatibility with the current Node.js version, and --force overrides it.

devEngines is for contributors, not consumers. It checks the environment before install, ci and run commands. Supported keys are cpu, os, libc, runtime and packageManager. Each entry takes a name, and optionally a version and an onFail value of warn, error or ignore. If onFail is omitted it behaves as error. The docs add that setting runtime or packageManager to an unsupported name fails inside the npm CLI.

Comparison

QuestionenginesdevEngines
Who is it forPeople installing your packagePeople working on your source
Default behaviorWarns onlyErrors unless onFail says otherwise
Can pin a package managerNoYes, through packageManager
Can pin the runtimeBy version rangeYes, through runtime
Can be made strictWith engine-strictThrough onFail

Why this is a security matter

Running an unexpected Node.js version can mean running without a fix. Runtimes age out of support, and a laptop or CI image left on an old version silently loses security patches. Pinning the runtime for contributors makes the intended version visible in the repository and makes a mismatch fail loudly rather than quietly.

Pinning the package manager has a related benefit. Different versions can resolve and write lockfiles differently, so a pinned tool reduces noisy lockfile diffs. For another approach to the same problem see Corepack and the packageManager field.

A setup that works

{
  "devEngines": {
    "runtime": { "name": "node", "version": ">=22", "onFail": "error" },
    "packageManager": { "name": "npm", "onFail": "error" }
  },
  "engines": { "node": ">=22" }
}

Choose a version range that matches a supported release line. For which lines are supported right now, read which Node.js version to run in production.

Steps

  1. Decide the minimum supported Node.js version from the current support table.
  2. Add devEngines with onFail set to error for runtime and package manager.
  3. Keep engines in sync, since consumers of a library still read it.
  4. Set engine-strict=true in .npmrc if you also want installs of dependencies to fail on incompatibility, and expect some friction.
  5. Make CI use the same Node version as the field, and fail if they differ.
  6. Review the range on a schedule, in line with the support dates.

Limits

These fields check the declared range. They do not prove the machine is patched, and they do not stop someone running an application with a different runtime in production. Enforce production versions in your image and deploy pipeline too. See also the engines field is advisory for the consumer side.

Safeguard flags end of life runtimes and vulnerable dependencies in your inventory. Try a free scan.

Quick check

What does devEngines do if onFail is missing?

It behaves as error, according to the npm docs.

Does engines block installs by default?

No. It only warns unless engine-strict is set.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.