Skip to content

mcmxcdev/check-my-engine

Repository files navigation

check-my-engine

Catch dependencies that quietly raise your project's minimum Node version.

You declare engines.node in package.json (say >=20) and your team runs the latest LTS (say v24). A dependency upgrade — direct or transitive — starts requiring engines.node >= 22 in the lockfile. Nothing flags it: engine-strict only checks the Node version of the developer running the install, not the range your project promises to support. check-my-engine reads the lockfile, finds every package whose engines.node no longer covers your declared range, and points you at the newest version of each that still fits.

npm (v9+, lockfileVersion: 3 — package-lock.json or npm-shrinkwrap.json) and pnpm (9+, lockfileVersion: '9.0') are supported at this time.

The rule

A dependency's engines.node is compared against your project's engines.node. Internally the covers check is semver.subset(projectRange, depRange). A non-covering dep is classified by whether your range's minimum Node (the floor) is still supported:

  • violation — the dep doesn't even support your floor (it needs a newer Node than your project's minimum). Fails the audit (exit 1).
  • warning — the dep supports your floor but not every higher version your range permits. This is the common "even-major / LTS-only" pattern: a dep that declares ^20 || ^22 || >=24 excludes the non-LTS 21.x / 23.x lines that >=20 technically allows. Reported, but does not fail the audit.
project engines.node dep engines.node result
>=20 >=18 ok (covers everything ≥20)
>=20 >=20 ok
>=20 >=22 violation (floor 20 broken)
>=20 ^20 || ^22 || >=24 warning (floor 20 ok; 21/23 excluded)
>=20 (none) / * ok (no constraint)

To silence a warning, tighten engines.node to match what you actually support (e.g. ^20 || ^22 || >=24) or add the package to ignore.

Install

npm install --save-dev check-my-engine

Usage

Audit the current graph

npx check-my-engine            # `check` is the default command
npx check-my-engine check

Example output:

✗ 2 dependencies require a newer Node than your project allows (>=20):

  needs-22@3.0.0 needs node >=22
    -> newest in-range version: needs-22@2.4.1
  child-needs-24@2.5.0 needs node >=24
    -> no published version supports >=20

check flags

Flag Description
-C, --cwd <dir> Project directory (default: current).
--node <range> Override or supply the project node range.
--json Machine-readable output.
--prod Skip devDependencies (npm only; no-op for pnpm).
--ignore <pkg> Ignore name or name@version (repeatable).
--no-suggest Skip registry lookups for in-range versions (offline).
--allow-prerelease Consider prerelease versions when suggesting.
--fallback-to-node-modules Read engines from node_modules when the lockfile omits them (npm only; no-op for pnpm).
--no-cache Skip the on-disk registry cache (always hit the network).

Registry cache

Suggestion lookups hit the npm registry once per package name. Responses are cached on disk so repeated runs — postinstall, CI, watch loops — stay fast and avoid registry rate limits. The cache is best-effort: a corrupt or unwritable cache degrades to a normal network fetch, never an error.

Setting Default Meaning
CHECK_MY_ENGINE_CACHE_DIR $XDG_CACHE_HOME/check-my-engine or ~/.cache/check-my-engine Cache directory.
CHECK_MY_ENGINE_CACHE_TTL 3600 (seconds) How long a cached packument stays fresh.
--no-cache cache on Bypass the cache for one run.

Debug logging

For development, set NODE_DEBUG=check-my-engine to trace registry traffic on stderr — each network fetch, registry hit, and cache hit. It is silent unless the namespace is enabled, so end-user runs (including postinstall) print nothing, and the trace never touches stdout (safe alongside --json).

$ NODE_DEBUG=check-my-engine npx check-my-engine
check-my-engine registry fetch: https://registry.npmjs.org/needs-22
check-my-engine registry hit: needs-22 (200, 12 versions)
check-my-engine cache hit: needs-22

Enforce on install

Wire the audit into npm's postinstall so an install that brings in an incompatible dependency fails loudly:

npx check-my-engine init

This adds (idempotently, preserving any existing postinstall):

{
  "scripts": {
    "postinstall": "check-my-engine check"
  }
}

After a full npm install / npm ci, the audit runs and exits non-zero if an installed dependency's engines.node doesn't cover your project range, so the install reports an error:

✗ 1 dependency requires a newer Node than your project allows (>=2):

  is-odd@3.0.1 needs node >=4
    -> newest in-range version: is-odd@2.0.0

It only reports — there's no rollback. The files npm wrote are left in place; fix it yourself by pinning an in-range version, widening engines.node, or adding the package to ignore.

Heads up: npm runs postinstall on a full npm install / npm ci, but not for a targeted npm install <pkg> / npm add <pkg> / npm update. Use the shell hook below to cover those, and/or run check-my-engine check in CI on the committed lockfile (npx check-my-engine check exits non-zero on any violation).

Cover targeted installs (shell hook)

Because npm skips postinstall for npm install <pkg>, add a small shell function that runs the audit after every dependency-changing npm command — including targeted installs:

# add to ~/.zshrc or ~/.bashrc (bash and zsh)
eval "$(check-my-engine shell-hook)"

You keep using npm exactly as before; the wrapper calls the real binary via command npm, then runs the audit and fails with a non-zero exit on a violation:

$ npm install is-odd
added 2 packages in 281ms
✗ 1 dependency requires a newer Node than your project allows (>=2):

  is-odd@3.0.1 needs node >=4
    -> newest in-range version: is-odd@2.0.0
  • Report-only, like init — it never modifies your files.
  • Only dependency-changing subcommands are audited; everything else (npm run, npm test, …) passes straight through. Global installs (-g) and directories without a package.json are skipped.
  • Prefers ./node_modules/.bin/check-my-engine; set CHECK_MY_ENGINE_BIN to override the binary used.

Configuration

Settings come from .check-my-engine.json or a checkMyEngine key in package.json (the rc file wins). CLI flags override config.

{
  "ignore": ["fsevents", "some-pkg@1.2.3"],
  "node": ">=20",
  "includeDev": true,
  "allowPrerelease": false
}
Key Type Default Meaning
ignore string[] [] Packages to skip (name or name@version).
node string Fallback/override range when no engines.node.
includeDev boolean true Audit devDependencies (--prod overrides).
allowPrerelease boolean false Allow prereleases when suggesting in-range versions.

Exit codes

Code Meaning
0 No violations (warnings may still be printed).
1 One or more violations found.
2 Usage/config error (no lockfile, or no project range and no --node).

--json output includes both violations and warnings arrays; ok is true when there are no violations (warnings don't affect it).

How it works

flowchart LR
  pkg["package.json engines.node"] --> core[audit core]
  lock["package-lock.json packages map"] --> core
  core --> viol{"covers()?"}
  viol -->|no| reg["registry: newest in-range version"]
  reg --> report[report + exit code]
  viol -->|yes| report
Loading
  • Project range comes from engines.node in package.json (or --node).
  • The graph and each dep's engines come from the npm v3 lockfile packages map (with an optional node_modules fallback), or the pnpm pnpm-lock.yaml v9 packages map.
  • Suggestions come from the registry's abbreviated metadata (application/vnd.npm.install-v1+json), which includes per-version engines.

Scope / limitations

  • npm package-lock.json / npm-shrinkwrap.json v3 (npm v9+) and pnpm pnpm-lock.yaml v9.0 (pnpm v9/v10/v11). yarn/bun not yet supported.
  • For pnpm, --prod and --fallback-to-node-modules are no-ops: the lockfile has no per-package dev flag and already carries engines.
  • Single-package projects (monorepo/workspace graphs not yet handled).
  • Only the node engine is considered.

License

MIT

About

Flags and blocks dependencies whose engines range does not cover your project's.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors