nodeseverity: can-fix
engine "node" mismatch

Node.js engine "node" requires version mismatch

Engine version mismatch

100% fixable~5 mindifficulty: beginner

Verified against Node.js Releases schedule, npm docs: engines field, pnpm docs: engine-strict · Updated May 2026

> quick_fix

A package in your dependency tree declares an engines.node range your installed Node does not satisfy. Read the required version from the error, switch with nvm use 22 or fnm use 22, then reinstall. Pin the version in .nvmrc and engines so this stops repeating.

# Read the required version from the error
# 'package@x.y.z requires Node >=22.0.0'

# Switch via nvm
nvm install 22
nvm use 22

# Pin for the project
echo '22' > .nvmrc

What causes this error

Every package.json can declare engines.node specifying a semver range of supported Node versions. npm warns by default; pnpm and yarn 4 fail hard. When the running Node major/minor falls outside the range (or any transitive dep's range), install or run errors. Common triggers: Vite 6 requires Node 20+, Next.js 16 requires Node 20+, Drizzle ORM requires Node 18.18+.

> advertisementAdSense placeholder

How to fix it

  1. 01

    step 1

    Read the version requirement from the error

    The error names the offending package and the required range. Compare to your installed version: node -v.

    Unsupported engine for next@16.0.0:
      wanted: { node: '>=20.0.0' }
      current: { node: 'v18.17.0' }
  2. 02

    step 2

    Switch Node with nvm or fnm

    Use a version manager. nvm (bash-based, portable) and fnm (Rust, fast) both honour .nvmrc. Avoid system-installed Node because every machine drifts.

    # nvm
    nvm install 22
    nvm use 22
    
    # fnm (faster, recommended)
    fnm install 22
    fnm use 22
  3. 03

    step 3

    Pin the version in .nvmrc

    A one-line .nvmrc at repo root makes nvm/fnm auto-switch on cd. New contributors and CI hit the same version automatically.

    echo '22' > .nvmrc
    
    # Optional: enable auto-switch in zsh
    echo 'autoload -U add-zsh-hook\nload-nvmrc() { [ -f .nvmrc ] && nvm use }' >> ~/.zshrc
  4. 04

    step 4

    Pin engines in package.json

    Declare the supported Node range in your package.json. pnpm and yarn 4 will refuse to install with the wrong version, catching mismatches before they cause runtime errors.

    {
      "engines": {
        "node": ">=22.0.0",
        "pnpm": ">=9.0.0"
      }
    }
  5. 05

    step 5

    Force pnpm to enforce the range

    By default pnpm warns. Set engine-strict=true in .npmrc to make it a hard error. Catches drift in CI before it reaches production.

    # .npmrc
    engine-strict=true
  6. 06

    step 6

    Reinstall after switching

    Some native modules (better-sqlite3, sharp, bcrypt) build per-Node-version C++ bindings. Switching majors invalidates them. Delete node_modules and reinstall.

    rm -rf node_modules
    pnpm install  # or npm ci, yarn install

Why engine "node" mismatch happens at the runtime level

package.json's engines field is read by package managers during install and at runtime if engine-strict is enabled. Internally, pnpm parses each installed package's engines.node range using semver.satisfies(process.version, range). When any package returns false, pnpm raises ERR_PNPM_UNSUPPORTED_ENGINE. The same logic runs on yarn 4, bun, and corepack-managed installs. Only npm defaults to warn-only behaviour. Native modules add a second layer: prebuilt binaries are compiled per-Node-major-version, and node-gyp invokes the loader's NAPI version check at require() time, throwing ERR_NAPI_INCOMPATIBLE_VERSION on mismatch.

Common debug mistakes for engine "node" mismatch

  • Using system Node (Homebrew, apt) instead of a version manager, then drifting between projects without realising.
  • Adding a dep that bumps engines to >=22 without updating .nvmrc, then surprised when CI fails.
  • Using nvm but forgetting to nvm use after rebooting; the shell drops back to the default version.
  • Installing a native module on Node 22, then switching to Node 20 and getting opaque NAPI errors at require.
  • Pinning engines.node to a single version (=22.0.0) instead of a range (>=22.0.0); patch updates will break it.

When engine "node" mismatch signals a deeper problem

Recurring engine-mismatch errors signal missing version-locking discipline across the development lifecycle. The architectural fix is to treat Node version as a runtime artifact: pinned in .nvmrc for local dev, packageManager + corepack for the package manager, engines for npm validation, and the same Node major in CI and production hosting. With these four locked, every developer and CI environment runs identical Node and package-manager versions. Without them, drift is inevitable: a dev installs a new dep on Node 22, CI on Node 20 runs older lockfile resolutions, and production on Node 18 hits runtime errors no one saw before.

Frequently asked questions

Why does npm only warn while pnpm fails?

npm's default behaviour for engines.node is a console warning (engine-strict=false). The reasoning is that engine fields are advisory and false positives could break installs. pnpm flips this default: engine-strict is true, so an unsupported engine fails the install. yarn 4 also fails. This is generally the right default for production: a dependency that declares Node 20+ as required is making a real claim; running it on Node 18 gambles on undocumented compatibility. Set engine-strict=true in .npmrc for npm projects too.

What about engines.npm or engines.pnpm?

Both are honored: a package can require a specific package-manager version. This catches projects that use lockfile-v9 features but a contributor is on pnpm 7 with lockfile-v6. The corepack tool (bundled with Node 16+) reads packageManager in package.json and pins the exact version per project: packageManager: pnpm@9.12.0. Combined with corepack enable, every contributor gets the same package manager without manually installing it.

Should I support multiple Node major versions?

For libraries published to npm, yes - support the active LTS plus any non-EOL versions in your engines range. Drop versions only when their minimum-required syntax (top-level await, structuredClone, Array.fromAsync) actually buys you cleaner code. For applications, target a single Node version that matches production. Multiple-version support in apps is wasted effort: production runs one version, CI runs the same, devs pin via .nvmrc.

Why does engine mismatch break my Vercel/Railway deploy?

Hosting platforms read engines.node from package.json to pick a Node binary at build time. Vercel will pick Node 22 if you specify >=22; if your dependency requires >=20, this works. But if some dep requires <22 (rare, but happens with old C++ addons), the build will fail. Always check both the engine ranges of your top-level deps and your hosting platform's supported versions. Vercel currently supports 18, 20, 22; Railway, Fly.io, and Render all support similar matrices.

disclosure:Errordex runs AdSense, has zero third-party affiliate or sponsored links, and occasionally links to the editor’s own paid digital products (clearly labelled). Every fix is manually verified against official sources listed in the “sources” sidebar. If a fix here didn’t work for you, please email so we can update the page.