Skip to content

fix: relax engines.node to >= 10 for N-API 3 compatibility - #20497

Open
Abdellox wants to merge 1 commit into
tailwindlabs:mainfrom
Abdellox:fix/relax-engines-node
Open

Abdellox wants to merge 1 commit into
tailwindlabs:mainfrom
Abdellox:fix/relax-engines-node

Conversation

@Abdellox

Copy link
Copy Markdown

oxide uses N-API 3, supported since Node.js 10.

Closes #20491

@Abdellox
Abdellox requested a review from a team as a code owner September 19, 2026 11:39
@greptile-apps

greptile-apps Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

This PR is not safe to merge until the artifact package engine declarations are aligned with the new Node 10 compatibility promise.

Reviews (1) · Last reviewed commit: "fix: relax engines.node to >= 10 for N-A..."

Comment thread crates/node/package.json
},
"engines": {
"node": ">= 20"
"node": ">= 10"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Artifact engines remain incompatible

Relaxing only the root package to Node 10 leaves every native artifact package at Node 20+, while the WASM artifact requires at least Node 20.19. Because these artifacts are optional dependencies of this package, Node 10–19 installations still receive incompatible-engine warnings or fail when strict engine checks are enabled. Update the artifact package manifests alongside the root manifest so the intended N-API 3 compatibility actually applies.

Knowledge Base Used: Oxide scanner and native bindings

@coderabbitai

coderabbitai Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Walkthrough

The engines.node requirement in crates/node/package.json changes from >= 20 to >= 10. This declares compatibility with older Node.js runtimes that support the package's N-API 3 binaries.

Priority: ⬇️ Low

Merge Risk: 🟡 Moderate · up to e11f1

The package advertises Node.js versions that may either fail installation or lack the required native API. Align all published engine ranges before merging.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: lowering the Node.js engine requirement to Node.js 10 for N-API 3 compatibility.
Description check ✅ Passed The description directly explains the Node.js 10 compatibility rationale and references the related issue.
Linked Issues check ✅ Passed The change for [#20491] lowers crates/node/package.json engines.node from >= 20 to >= 10. This matches the required N-API 3 runtime floor and removes the build-time Node.js 20 requirement for …
Out of Scope Changes check ✅ Passed The supplied whole-PR summary reports one change in crates/node/package.json: the engines.node value changes from >= 20 to >= 10. This change directly implements [#20491]. No unrelated change …

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 024282b2-5053-4e09-adc4-c6d145722bf6

📥 Commits

Reviewing files that changed from the base of the PR and between 41d9cae and e11f1c4.

📒 Files selected for processing (1)
  • crates/node/package.json

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Comment thread crates/node/package.json
},
"engines": {
"node": ">= 20"
"node": ">= 10"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

sed -n '35,90p' crates/node/package.json
find crates/node/npm -name package.json -maxdepth 3 -print -exec sed -n '1,40p' {} \;
rg -n 'optionalDependencies|oxide-|wasm32|require\(|engines' crates/node

Repository: tailwindlabs/tailwindcss

Length of output: 14716


🌐 Web query:

npm engine-strict optionalDependencies incompatible engines behavior

💡 Result:

<search_synthesis>
When the engine-strict configuration flag is set to true, npm enforces engines compatibility for all dependencies, including optionalDependencies [1][2]. If a package&#39;s engines field is incompatible with the current environment (e.g., Node.js or npm version), the installation will fail with an EBADENGINE error [3][4]. Key behaviors regarding this interaction include: 1. Enforcement: By default, the engines field is advisory and only produces warnings [5][6]. Enabling engine-strict=true changes this behavior, causing npm to refuse to install any package that does not satisfy its declared engine requirements [1][2]. 2. Optional Dependencies: Because optionalDependencies are treated as standard dependencies during the resolution and installation phase, they are subject to the same engine-strict checks as required dependencies [3]. If an optional dependency is incompatible with your environment, engine-strict=true will cause the entire npm install process to fail, even though the dependency is technically "optional" [3]. 3. Overrides: The engine-strict enforcement can be bypassed by using the --force flag [1][2]. When --force is used, npm will allow the installation of packages even if they have incompatible engines declarations [1][2]. 4. Platform vs. Engine: Note that optionalDependencies also have separate mechanisms for platform compatibility (using os, cpu, and libc fields in package.json) [7][8]. These platform-specific checks are distinct from engines version checks and are handled differently by npm&#39;s installer [7]. In summary, while optionalDependencies are intended to be non-blocking for installation failures, the engine-strict flag overrides this by making engine compatibility a hard requirement for all packages in the dependency tree [3][1].
</search_synthesis>

<source_evidence>

<title>Config | npm Docs</title> https://docs.npmjs.com/cli/v12/using-npm/config/ ### `engine-strict` ... - Default: false - Type: Boolean ... If set to true, then npm will stubbornly refuse to install (or even consider installing) any package that claims to not be compatible with the current Node.js version. ... This can be overridden by setting the `--force` flag. ... ### `force` ... - Allow clobbering non-npm files in global installs. - Allow the `npm version` command to work on an unclean git repository. - Allow deleting the cache folder with `npm cache clean`. - Allow installing packages that have an `engines` declaration requiring a different version of npm. - Allow installing packages that have an `engines` declaration requiring a different version of `node`, even if `--engine-strict` is enabled. - Allow `npm audit fix` to install modules outside your stated dependency range (including SemVer-major changes). - Allow unpublishing all versions of a published package. - Allow conflicting peerDependencies to be installed in the root project. - Implicitly set `--yes` during `npm init`. - Allow clobbering existing values in `npm pkg` - Allow unpublishing of entire packages (not just a single version). ... dependencies that cannot be installed on the current platform or engine (a non-matching `os`, `cpu`, or `libc`) are not flagged, because their install scripts never run. ... ### `optional` <title>config | npm Docs</title> https://docs.npmjs.com/cli/v9/using-npm/config/ ### `engine-strict` ... - Default: false - Type: Boolean ... If set to true, then npm will stubbornly refuse to install (or even consider installing) any package that claims to not be compatible with the current Node.js version. ... This can be overridden by setting the `--force` flag. ... ### `force` ... - Default: false ... against unfortunate side ... , common mistakes ... unnecessary performance degradation ... - Allow clobbering non-npm files in global installs. - Allow the `npm version` command to work on an unclean git repository. - Allow deleting the cache folder with `npm cache clean`. - Allow installing packages that have an `engines` declaration requiring a different version of npm. - Allow installing packages that have an `engines` declaration requiring a different version of `node`, even if `--engine-strict` is enabled. - Allow `npm audit fix` to install modules outside your stated dependency range (including SemVer-major changes). - Allow unpublishing all versions of a published package. - Allow conflicting peerDependencies to be installed in the root project. - Implicitly set `--yes` during `npm init`. - Allow clobbering existing values in `npm pkg` - Allow unpublishing of entire packages (not just a single version). ... ### `optional` ... - Default: null - Type ... null or Boolean - DEPRECATED: Use `--omit=optional` to exclude optional dependencies, or ... include=optional` to include them <title>[BUG] Option engine-strict=true is not compatible with --omit=dev · Issue `#6805` · npm/cli</title> GitHub issue 6805 in npm/cli (link omitted to avoid creating a cross-reference) # Issue: npm/cli `#6805` - Repository: npm/cli | the package manager for JavaScript | 10K stars | JavaScript ## [BUG] Option engine-strict=true is not compatible with --omit=dev - Author: [`@sempasha`](https://github.com/sempasha) - State: closed (completed) - Labels: Bug, Priority 1, Release 9.x, Release 10.x - Assignees: [`@wraithgar`](https://github.com/wraithgar) - Reactions: 👍 1 - Created: 2023-09-14T15:36:10Z - Updated: 2025-06-26T20:20:37Z - Closed: 2025-06-26T20:20:37Z - Closed by: [`@wraithgar`](https://github.com/wraithgar) ### Is there an existing issue for this? - [X] I have searched the existing issues ### This issue exists in the latest npm version - [X] I am using the latest npm ### Current Behavior Running `npm install --omit=dev` with config option `engine-strict=true` leads to compatibility errors even for dependencies of any kind. ### Expected Behavior While running `npm install --omit=dev` with config option `engine-strict=true` npm ignores compatibility errors for dev only dependencies. ### Steps To Reproduce Let&`#39`;s say you have package with package.json manifest ```json { "name": "uncompatible-package", "version": "1.0.0", "engines": { "node": ">=100500" } } ``` And you have application package, where you want to have uncompatible-package as dev dependency ```json { "name": "application", "version": "1.0.0", "devDependencies": { "uncompatible-package": "./uncompatible-package-1.0.0.tgz" } } ``` And you set `engine-strict=true` option for your application package ```sh $ npm config set engine-strict true ``` And when you want to install only production dependencies you have compatibility error ```sh $ npm install --omit=dev npm ERR! code EBADENGINE npm ERR! engine Unsupported engine npm ERR! engine Not compatible with your version of node/npm: uncompatible-package@1.0.0 npm ERR! notsup Not compatible with your version of node/npm: uncompatible-package@1.0.0 npm ERR! notsup Required: {"node":">=100500"} npm ERR! notsup Actual: {"npm":"10.1.0","node":"v20.6.1"} npm ERR! A complete log of this run can be found in: npm ERR! /home/sempasha/.npm/_logs/2023-09-14T15_31_44_507Z-debug-0.log ``` ### Environment - npm: 10.1.0 - Node.js: 20.6.1 - OS Name: Fedora Linux - System Model Name: PC - npm config: ```ini engine-strict = true ``` --- ### Timeline **sempasha** added label `Bug`; added label `Needs Triage`; added label `Release 10.x` · Sep 14, 2023 at 3:36pm **sempasha** changed the title from "Option engine-strict=true is not compatible with --omit=dev" to "[BUG] Option engine-strict=true is not compatible with --omit=dev" · Sep 14, 2023 at 5:54pm **lukekarrys** added label `Release 9.x` · Oct 6, 2023 at 4:18pm **`@romainmenke`** commented · Oct 9, 2023 at 6:52am > We are also affected by this. > > We author packages that still support node 14, 16, ... but we have dev dependencies to build our own packages that only support node 18 and later. > > We had hoped to declare these as dev dependencies and use `--omit=dev` as a fix. **wraithgar** removed label `Needs Triage`; added label `Priority 1` · Nov 8, 2023 at 4:42pm **wraithgar** assigned [`@wraithgar`](https://github.com/wraithgar) · Nov 9, 2023 at 5:46pm **colinrotherham** mentioned this in PR [`#11823`: Check for unsupported `"engines"` package.json fields](https://github.com/webdriverio/webdriverio/pull/11823) · Dec 6, 2023 at 10:08pm **colinrotherham** mentioned this in issue [`#11868`: [💡 Feature]: Check for unsupported `"engines"` package.json fields](https://github.com/webdriverio/webdriverio/issues/11868) · Dec 14, 2023 at 9:28am **`@serhalp`** commented · May 29, 2025 at 3:29pm > For anyone else landing here, you can work around this by using https://github.com/voxpelli/node-installed-check in…[truncated] <title>accepted/000-package-resolution-nodejs-version.md</title> https://github.com/shalvah/rfcs/blob/package-resolution-nodejs-version/accepted/000-package-resolution-nodejs-version.md # accepted/000-package-resolution-nodejs-version.md - Branch: package-resolution-nodejs-version - Repository: shalvah/rfcs --- # Resolve packages based on Node.js version ## Summary npm should be able to accept a semver range of a package and install the highest available version that supports the current Node.js version. ## Motivation Developers often make apps/libraries that need to support multiple versions of the same package, which have different minimum Node.js versions. A good use case for this is to allow "progressive upgrades": - my library supports Node.js 10.x and above - package X releases `newVersion`, which supports Node.js 12.x and above - I change my package X constraint from `"oldVersion"` to `"oldVersion || newVersion"` - My code will then use `newVersion` when my code is running on 12.x, and fallback to `oldVersion` when running on 10.x - This gives several benefits: - I can test out `newVersion` locally over time before upgrading the production server&`#39`;s Node.js version - I can support older Node.js versions while benefitting from package X&`#39`;s newer versions on newer Node.js versions Right now, npm always installs the highest available version of the package, even if it isn&`#39`;t supported on my Node.js version, making this hard. ## Detailed Explanation npm should take the current Node.js version into consideration when determining valid package versions to install. For instance, Mocha v9 dropped support for Node.js 10.x (using the `engines` field). However, in my library, Node.js 10.x is still supported for end users, so I&`#39`;d like to use Mocha v8 to run tests on Node.js 10.x and v9 on 12.x. There are no major API changes, so this should be easy to do. Currently, specifying a semver range like `"mocha": "^8.0.0 || ^9.0.0"` doesn&`#39`;t work. npm happily installs v9 even on Node.js 10.x (although it outputs a warning): ``` ❯ npm i npm WARN EBADENGINE Unsupported engine { package: &`#39`;mocha@9.0.1&`#39`;, npm WARN EBADENGINE required: { node: &`#39`;>= 12.0.0&`#39`; }, npm WARN EBADENGINE current: { node: &`#39`;v10.24.1&`#39`;, npm: &`#39`;7.17.0&`#39`; } } added 92 packages, and audited 93 packages in 1s ❯ npm list mocha in@ C:\Users\shalvah\<projectpath> `-- mocha@9.0.1 ``` With the `--engine-strict` flag, the install is stopped: ``` ❯ npm i --engine-strict npm ERR! code EBADENGINE npm ERR! engine Unsupported engine npm ERR! engine Not compatible with your version of node/npm: mocha@9.0.1 npm ERR! notsup Not compatible with your version of node/npm: mocha@9.0.1 npm ERR! notsup Required: {"node":">= 12.0.0"} npm ERR! notsup Actual: {"npm":"7.17.0","node":"v10.24.1"} ``` The goal is to change this so that, on Node.js 10.x, version 8 is installed instead in both cases. ## Rationale and Alternatives Current workarounds: 1. Maintain separate copies of `package.json` for different Node.js versions (such as a `package.json` and a `package.10.x.json`, with the latter referencing the older version of the package), and switch between them when on a different Node.js version 2. Manually replace the package version in `package.json` when on a different Node.js version. Both these options are clunky, as they involve either manual work or additional scripting. ## Implementation During `npm install`: - Fetch package versions satisfying the semver range - Get the current Node.js version (`process.version`). If there is an `engines.node` field in the root package, this overrides the value from `process.version`. - Find the highest which supports the current Node.js version. - If there is none, fallback to the current behaviour (install the highest available, or fail if `--engine-strict` is set). - If there are valid versions for this Node.js version, install the highest of those. This will apply all the way down the tree. A package is defined as supporting a Node.js version if it does not define a…[truncated] <title>package.json | npm Docs</title> https://docs.npmjs.com/cli/v12/configuring-npm/package-json/ ## optionalDependencies ... If a dependency can be used, but you would like npm to proceed if it cannot be found or fails to install, then you may put it in the `optionalDependencies` object. This is a map of package name to version or URL, just like the `dependencies` object. The difference is that build failures do not cause installation to fail. Running `npm install --omit=optional` will prevent these dependencies from being installed. ... You can specify ... your stuff works ... You can also use the "engines" field to specify which versions of npm are capable of properly installing your program. For example: "npm": "~1.0.20" ... Unless the user has set the `engine-strict` config flag, this field is advisory only and will only produce warnings when your package is installed as a dependency. ... engines` and ... devEngines ... , whereas `devEngines

Citations:


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- loader and adjacent files ---'
find crates/node -maxdepth 2 -type f \( -name 'index.js' -o -name '*.mjs' -o -name '*.cjs' -o -name 'package.json' \) -print
printf '%s\n' '--- crates/node/index.js ---'
cat -n crates/node/index.js
printf '%s\n' '--- package manifests: engines and platform selectors ---'
python3 - <<'PY'
import json
from pathlib import Path
for p in sorted(Path('crates/node/npm').glob('*/package.json')):
    d=json.loads(p.read_text())
    print(f"{p}: name={d.get('name')}; engines={d.get('engines')}; os={d.get('os')}; cpu={d.get('cpu')}; libc={d.get('libc')}; main={d.get('main')}")
PY
printf '%s\n' '--- loader references and fallback names ---'
rg -n --glob '!package-lock.json' --glob '!pnpm-lock.yaml' 'oxide-(android|darwin|freebsd|linux|wasm|win32)|require|try|catch|fallback|wasm' crates/node/index.js crates/node/*.js crates/node/*.mjs crates/node/*.cjs crates/node/package.json

Repository: tailwindlabs/tailwindcss

Length of output: 342


🏁 Script executed:

#!/bin/bash
set -u
printf '%s\n' '--- tracked loader candidates ---'
git ls-files crates/node | rg '(^|/)(index\.(js|cjs|mjs)|package\.json|.*binding.*|.*loader.*|.*wasm.*)$' || true
printf '%s\n' '--- oxide package references outside generated artifacts ---'
rg -n --glob '!node_modules/**' --glob '!target/**' --glob '!dist/**' --glob '!build/**' 'oxide-(android|darwin|freebsd|linux|wasm|win32)|tailwindcss-oxide|wasm32-wasi' crates/node .github package.json pnpm-workspace.yaml 2>/dev/null || true
printf '%s\n' '--- node package tree ---'
git ls-files crates/node | sed -n '1,160p'

Repository: tailwindlabs/tailwindcss

Length of output: 10737


Align every published optional package with the root Node.js support range.

The root package advertises Node.js >= 10, but the native platform packages require >= 20, and @tailwindcss/oxide-wasm32-wasi requires ^20.19.0 || ^22.13.0 || >=23.5.0. The WASI package is also an optional dependency without an os or cpu restriction. With engine-strict=true, npm can reject these incompatible optional packages with EBADENGINE before any loader fallback runs. If Node.js 10 remains supported, assign each native package its actual compatible minimum and gate or otherwise constrain the WASI package. Otherwise, raise the root package minimum to >= 20.


🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

sed -n '1,80p' crates/node/Cargo.toml
rg -n 'napi[0-9]|napi::|#[[:space:]]*\[napi|engines' crates/node --glob '!target/**'

Repository: tailwindlabs/tailwindcss

Length of output: 2265


🌐 Web query:

Node.js official Node-API version matrix N-API 4 Node 10.16

💡 Result:

<search_synthesis>
According to the official Node.js Node-API version matrix, Node-API version 4 is supported in Node.js v10.16.0 and all later versions [1][2]. Node.js 10.16.0, which was an LTS release, explicitly introduced support for Node-API version 4 [3]. Node-API versions are additive, meaning that Node.js versions supporting a later Node-API version also support all previous versions [1][2].
</search_synthesis>

<source_evidence>

<title>Node-API | Node.js v26.7.0 Documentation</title> https://nodejs.org/api/n-api.html - Node-API version matrix ... ### Node-API version matrix# ... Up until version 9, Node-API versions were additive and versioned independently from Node.js. This meant that any version was an extension to the previous version in that it had all of the APIs from the previous version with some additions. Each Node.js version only supported a single Node-API version. For example v18.15.0 supports only Node-API version 8. ABI stability was achieved because 8 was a strict superset of all previous versions. ... As of version 9, while Node-API versions continue to be versioned independently, an add-on that ran with Node-API version 9 may need code updates to run with Node-API version 10. ABI stability is maintained, however, because Node.js versions that support Node-API versions higher than 8 will support all versions between 8 and the highest version they support and will default to providing the version 8 APIs unless an add-on opts into a higher Node-API version. This approach provides the flexibility of better optimizing existing Node-API functions while maintaining ABI stability. Existing add-ons can continue to run without recompilation using an earlier version of Node-API. If an add-on needs functionality from a newer Node-API version, changes to existing code and recompilation will be needed to use those new functions anyway. ... In versions of Node.js that support Node-API version 9 and later, defining `NAPI_VERSION=X` and using the existing add-on initialization macros will bake in the requested Node-API version that will be used at runtime into the add-on. If `NAPI_VERSION` is not set it will default to 8. ... This table may not be up to date in older streams, the most up to date information is in the latest API documentation in: Node-API version matrix ... | Node-API version | Supported In | | --- | --- | | 10 | v22.14.0+, 23.6.0+ and all later versions | | 9 | v18.17.0+, 20.3.0+, 21.0.0 and all later versions | | 8 | v12.22.0+, v14.17.0+, v15.12.0+, 16.0.0 and all later versions | | 7 | v10.23.0+, v12.19.0+, v14.12.0+, 15.0.0 and all later versions | | 6 | v10.20.0+, v12.17.0+, 14.0.0 and all later versions | | 5 | v10.17.0+, v12.11.0+, 13.0.0 and all later versions | | 4 | v10.16.0+, v11.8.0+, 12.0.0 and all later versions | | 3 | v6.14.2*, 8.11.2+, v9.11.0+*, 10.0.0 and all later versions | | 2 | v8.10.0+*, v9.3.0+*, 10.0.0 and all later versions | | 1 | v8.6.0+**, v9.0.0+*, 10.0.0 and all later versions | ... .0. We recommend Node-API version 3 <title>Node-API | Node.js v26.8.1 Documentation</title> https://nodejs.org/docs/latest-v26.x/api/n-api.html ### Node-API version matrix# ... Up until version 9, Node-API versions were additive and versioned independently from Node.js. This meant that any version was an extension to the previous version in that it had all of the APIs from the previous version with some additions. Each Node.js version only supported a single Node-API version. For example v18.15.0 supports only Node-API version 8. ABI stability was achieved because 8 was a strict superset of all previous versions. ... As of version 9, while Node-API versions continue to be versioned independently, an add-on that ran with Node-API version 9 may need code updates to run with Node-API version 10. ABI stability is maintained, however, because Node.js versions that support Node-API versions higher than 8 will support all versions between 8 and the highest version they support and will default to providing the version 8 APIs unless an add-on opts into a higher Node-API version. This approach provides the flexibility of better optimizing existing Node-API functions while maintaining ABI stability. Existing add-ons can continue to run without recompilation using an earlier version of Node-API. If an add-on needs functionality from a newer Node-API version, changes to existing code and recompilation will be needed to use those new functions anyway. ... In versions of Node.js that support Node-API version 9 and later, defining`NAPI_VERSION=X` and using the existing add-on initialization macros will bake in the requested Node-API version that will be used at runtime into the add-on. If`NAPI_VERSION` is not set it will default to 8. ... This table may not be up to date in older streams, the most up to date information is in the latest API documentation in: Node-API version matrix ... | Node-API version | Supported In | | --- | --- | | 10 | v22.14.0+, 23.6.0+ and all later versions | | 9 | v18.17.0+, 20.3.0+, 21.0.0 and all later versions | | 8 | v12.22.0+, v14.17.0+, v15.12.0+, 16.0.0 and all later versions | | 7 | v10.23.0+, v12.19.0+, v14.12.0+, 15.0.0 and all later versions | | 6 | v10.20.0+, v12.17.0+, 14.0.0 and all later versions | | 5 | v10.17.0+, v12.11.0+, 13.0.0 and all later versions | | 4 | v10.16.0+, v11.8.0+, 12.0.0 and all later versions | | 3 | v6.14.2*, 8.11.2+, v9.11.0+*, 10.0.0 and all later versions | | 2 | v8.10.0+*, v9.3.0+*, 10.0.0 and all later versions | | 1 | v8.6.0+**, v9.0.0+*, 10.0.0 and all later versions | ... Node-API version <title>Node.js — Node.js 10.16.0 (LTS)</title> https://nodejs.org/en/blog/release/v10.16.0 - [b450ee28e3] - doc: fix up N-API support matrix (Michael Dawson)`#26377` ... - [1ae6853015] - doc,n-api: update matrix for N-API version 4 (Richard Lau) ... - [98193d1d4d] - doc,tools: updates for 6.x End-of-Life (Richard Lau)`#27658` ... - [2643801d9d] - n-api: improve performance creating strings (Anthony Tuininga)`#26439` ... 588daef0 ... 259 ... - [48a5241b46] - (SEMVER-MINOR) n-api: mark thread-safe function as stable (Gabriel Schulhof)`#25556` ... node-v10.16.0.pkg macOS 64-bit Binary: https://nodejs.org/dist/v10.16 ... 0/node-v10.16.0-darwin-x64. ... .gz Linux 64-bit Binary: https://nodejs.org/dist/v10.16.0/node-v10.16.0-linux-x64.tar.xz Linux PPC LE 64-bit Binary: https://nodejs.org/dist/v10.16.0/node-v10.16.0-linux-ppc64le.tar.xz Linux s390x 64-bit Binary: https://nodejs.org/dist/v10.16.0/node-v10.16.0-linux-s390x.tar.xz AIX 64-bit Binary: https://nodejs.org/dist/v10.16.0/node-v10.16.0-aix-ppc64.tar.gz SmartOS 64-bit Binary: https://nodejs.org/dist/v10.16.0/node-v10.16.0-sunos-x64.tar.xz ARMv6 32-bit Binary: https://nodejs.org/dist/v10.16.0/node-v10.16.0-linux-armv6l.tar.xz ARMv7 32-bit Binary: https://nodejs.org/dist/v10.16.0/node-v10.16.0-linux-armv7l.tar.xz ARMv8 64-bit Binary: https://nodejs.org/dist/v10.16.0/node-v10.16.0-linux-arm64.tar.xz Source Code: https://nodejs.org/dist/v10.16.0/node-v10.16.0.tar.gz Other release files: https://nodejs.org/dist/v10.16.0/ Documentation: https://nodejs.org/docs/v10.16.0/api/ <title>Node-API | Node.js v16.20.2 Documentation</title> https://nodejs.org/download/release/latest-v16.x/docs/api/n-api.html ### Node-API version matrix# ... Node-API versions are additive and versioned independently from Node.js. Version 4 is an extension to version 3 in that it has all of the APIs from version 3 with some additions. This means that it is not necessary to recompile for new versions of Node.js which are listed as supporting a later version. ... | | 1 | 2 | 3 | | --- | --- | --- | --- | | v6.x | | | v6.14.2* | | v8.x | v8.6.0** | v8.10.0* | v8.11.2 | | v9.x | v9.0.0* | v9.3.0* | v9.11.0* | | ≥ v10.x | all releases | all releases | all releases | ... | | 4 | 5 | 6 | 7 | 8 | | --- | --- | --- | --- | --- | --- | | v10.x | v10.16.0 | v10.17.0 | v10.20.0 | v10.23.0 | | | v11.x | v11.8.0 | | | | | | v12.x | v12.0.0 | v12.11.0 | v12.17.0 | v12.19.0 | v12.22.0 | | v13.x | v13.0.0 | v13.0.0 | | | | | v14.x | v14.0.0 | v14.0.0 | v14.0.0 | v14.12.0 | v14.17.0 | | v15.x | v15.0.0 | v15.0.0 | v15.0.0 | v15.0.0 | v15.12.0 | | v16.x | v16.0.0 | v16.0.0 | v16.0.0 | v16.0.0 | v16.0.0 | ... * Node-API was experimental. ... Node.js ... .0.0 included Node-API as experimental. It was released as Node-API version 1 but continued to evolve until Node.js ... .6.0. The API is different in versions prior to Node.js 8.6.0. We recommend Node-API version 3 or later. <title>Node-API | Node.js v16.10.0 Documentation</title> https://nodejs.org/download/release/v16.10.0/docs/api/n-api.html ### Node-API version matrix# ... Node-API versions are additive and versioned independently from Node.js. Version 4 is an extension to version 3 in that it has all of the APIs from version 3 with some additions. This means that it is not necessary to recompile for new versions of Node.js which are listed as supporting a later version. ... | | 1 | 2 | 3 | | --- | --- | --- | --- | | v6.x | | | v6.14.2* | | v8.x | v8.6.0** | v8.10.0* | v8.11.2 | | v9.x | v9.0.0* | v9.3.0* | v9.11.0* | | ≥ v10.x | all releases | all releases | all releases | ... | | 4 | 5 | 6 | 7 | 8 | | --- | --- | --- | --- | --- | --- | | v10.x | v10.16.0 | v10.17.0 | v10.20.0 | v10.23.0 | | | v11.x | v11.8.0 | | | | | | v12.x | v12.0.0 | v12.11.0 | v12.17.0 | v12.19.0 | v12.22.0 | | v13.x | v13.0.0 | v13.0.0 | | | | | v14.x | v14.0.0 | v14.0.0 | v14.0.0 | v14.12.0 | v14.17.0 | | v15.x | v15.0.0 | v15.0.0 | v15.0.0 | v15.0.0 | v15.12.0 | | v16.x | v16.0.0 | v16.0.0 | v16.0.0 | v16.0.0 | v16.0.0 | ... * Node-API was experimental. ... ** Node.js ... .0.0 included Node-API as experimental. It was released as Node-API version 1 but continued to evolve until Node.js 8.6.0. The API is different in versions prior to Node.js 8.6.0. We recommend Node-API version 3 or later.

Citations:


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- crates/node/package.json ---'
sed -n '1,70p' crates/node/package.json
printf '%s\n' '--- crates/node/src/lib.rs (annotated) ---'
cat -n crates/node/src/lib.rs | sed -n '1,215p'
printf '%s\n' '--- engine declarations under crates/node ---'
rg -n -C 2 '"node"[[:space:]]*:' crates/node --glob 'package.json'
printf '%s\n' '--- dependency lock entries ---'
rg -n -A 12 -B 2 'name = "(napi|napi-derive|napi-build)"' Cargo.lock crates/node/Cargo.lock 2>/dev/null || true

Repository: tailwindlabs/tailwindcss

Length of output: 13217


🌐 Web query:

napi-rs 3.11.0 napi4 Cargo feature minimum Node-API version generated addon NAPI_VERSION

💡 Result:

<search_synthesis>
In napi-rs, the napi4 Cargo feature corresponds to Node-API version 4 [1][2]. This feature is the default in napi-rs and is required for core functionality including ThreadsafeFunction, deferred/async runtime integration, and cross-thread reference cleanup [1]. Key details regarding the napi4 feature and Node-API versions: 1. Cumulative Features: The napiN features in napi-rs are cumulative [1]. Enabling napi4 automatically enables napi3, napi2, and napi1 [1][2]. 2. Minimum Node-API Version: The selected napiN feature represents the minimum Node-API capability your addon relies on [1]. While napi-rs uses these features to gate specific APIs, the actual runtime compatibility depends on the Node.js version used by the end user [1][3]. 3. Default Status: napi4 is the default feature for napi-rs projects [1][4]. It is required for many common asynchronous operations, such as spawning futures or using tokio_rt [5][6]. 4. Project Configuration: When using the napi-rs CLI (napi new), the tool prompts for a minimum Node-API level, which it then writes to both the Cargo.toml (as a napiN feature) and the package.json (as an engines.node requirement) to ensure consistency [7][8]. While napi-rs provides these feature flags to manage compatibility, you should choose the lowest Node-API level that supports the APIs your addon requires, then test against the oldest Node.js runtime that supports that level [1][7]. Note that some advanced features or integrations may implicitly require a higher Node-API level than napi4 [8].
</search_synthesis>

<source_evidence>

<title>Cargo features – NAPI-RS</title> https://napi.rs/docs/concepts/cargo-features The `napi` feature set controls which Node-API symbols and high-level Rust APIs are compiled into an addon. Choose the lowest Node-API level that provides the APIs you use, then enable only the optional integrations your crate needs. ... `napi` enables these features by default: ... ``` default = ["napi4", "dyn-symbols"] ``` ... This means adding `features = ["napi2"]` without disabling defaults still builds for Node-API 4. To target a level below 4, disable defaults explicitly and decide whether to retain dynamic symbol loading: ... The `napi1` through `napi10` features are cumulative. For example, `napi8` enables `napi7`, which enables every lower level. The selected level is the minimum Node-API capability your addon may rely on. ... | Feature | Representative napi-rs APIs gated at this level | | --- | --- | | `napi1` | Base values, functions, objects, arrays, buffers, async work, Promises, and references. | | `napi2` | Access to the libuv event loop with `Env::get_uv_event_loop` on native targets. | | `napi3` | Environment cleanup hooks. | | `napi4` | ThreadsafeFunction, deferred/async runtime integration, and napi-rs&`#39`;s cross-thread reference cleanup machinery. This is the default. | | `napi5` | JavaScript `Date`, finalizers, and related object/property APIs. | | `napi6` | BigInt and BigInt typed arrays, per-environment instance data, and additional object/ArrayBuffer APIs. | | `napi7` | Detaching and testing detached ArrayBuffers. | | `napi8` | Async cleanup hooks, object freeze/seal, and type-tagging APIs. | | `napi9` | Global symbols, module file names, and JavaScript `SyntaxError` creation/throwing. | | `napi10` | External Latin-1/UTF-16 strings and dedicated property-key creation APIs. | ... Node.js has backported some Node-API levels to multiple release lines, so a single Node major version is not a precise compatibility test. Check the official Node-API version matrix and the actual runtime value: ... Inside native code, `Env::get_napi_version()` reads the same value. Your package&`#39`;s supported-runtime claim should be no broader than both the selected Node-API level and the runtime versions you actually test. ... ### # Choosing a level ... 1. Start with the template/default `napi4` unless a dependency or required API dictates otherwise. 2. Raise it when the compiler shows that a needed API is feature-gated. 3. Test the oldest runtime in the resulting compatibility range. 4. Keep the CLI&`#39`;s `minNodeApiVersion`, Cargo features, package `engines`, and CI matrix consistent. ... Raising the feature can make the resulting addon unloadable or unusable on older runtimes. Lowering it removes Rust APIs at compile time and is the safest way to discover accidental dependencies on a newer level. ... targets, `dyn- ... functions from the host process when the addon initializes instead ... requiring every symbol ... be resolved by ... platform linker. It is enabled by ... This is especially useful across operating systems and Node-compatible hosts with different native linking behavior. Missing functions use generated stubs so symbol loading can continue, but calling a missing API still fails. `dyn-symbols` does not turn Node-API 10 into Node-API 4. ... ", default-features = ... ### # `node_version_detect` ... `node_version_detect` reads and caches the host Node version during module registration. napi-rs uses it to select a few guarded optimized paths, including newer property-creation paths when the required symbols and companion features are enabled. ... It is not a general compatibility guard around every Node-API call. Your code must still respect the selected Node-API feature and runtime support matrix. ... ## # Recommended published-addon baseline ... ``` [dependencies] napi = { version = "3", default-features = false, features = ["napi4", "dyn-symbols"] } napi-derive = "3" [build-dependencies] napi-build = "2" ``` ... …[truncated] <title>crates/napi/Cargo.toml at 529a78d15c0c7d6ca6d4a732c5e335f9de701879 · napi-rs/napi-rs</title> https://github.com/napi-rs/napi-rs/blob/529a78d15c0c7d6ca6d4a732c5e335f9de701879/crates/napi/Cargo.toml # File: napi-rs/napi-rs/crates/napi/Cargo.toml - Repository: napi-rs/napi-rs | A framework for building compiled Node.js add-ons in Rust via Node-API | 8K stars | Rust - Branch: 529a78d15c0c7d6ca6d4a732c5e335f9de701879 ```toml [package] authors = ["Nathan Sobo <nathan@github.com>", "Yinan Long <lynweklm@gmail.com>"] description = "N-API bindings" edition = "2021" keywords = ["NodeJS", "Node", "FFI", "NAPI", "n-api"] license = "MIT" name = "napi" readme = "README.md" repository = "https://github.com/napi-rs/napi-rs" rust-version.workspace = true version = "3.9.2" [lib] doctest = false [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] [package.metadata.workspaces] independent = true [features] async = ["tokio_rt"] chrono_date = ["chrono", "napi5"] # Enable deprecated types and traits for compatibility compat-mode = [] default = ["napi4", "dyn-symbols"] deferred_trace = ["napi4"] error_anyhow = ["anyhow"] experimental = ["napi-sys/experimental"] full = [ "latin1", "napi10", "async", "serde-json", "experimental", "chrono_date", ] object_indexmap = ["indexmap"] latin1 = ["encoding_rs"] napi1 = [] napi2 = ["napi1", "napi-sys/napi2"] napi3 = ["napi2", "napi-sys/napi3"] napi4 = ["napi3", "napi-sys/napi4"] napi5 = ["napi4", "napi-sys/napi5"] napi6 = ["napi5", "napi-sys/napi6"] napi7 = ["napi6", "napi-sys/napi7"] napi8 = ["napi7", "napi-sys/napi8"] napi9 = ["napi8", "napi-sys/napi9"] napi10 = ["napi9", "napi-sys/napi10"] web_stream = ["futures-core", "tokio-stream", "napi4", "tokio_rt"] noop = [] serde-json = ["serde", "serde_json"] serde-json-ordered = ["serde-json", "serde_json/preserve_order"] tokio_fs = ["tokio/fs"] tokio_full = ["tokio/full"] tokio_io_std = ["tokio/io-std"] tokio_io_util = ["tokio/io-util"] tokio_macros = ["tokio/macros"] tokio_net = ["tokio/net"] tokio_process = ["tokio/process"] tokio_rt = ["tokio", "napi4"] tokio_signal = ["tokio/signal"] tokio_sync = ["tokio/sync"] tokio_test_util = ["tokio/test-util"] tokio_time = ["tokio/time"] dyn-symbols = ["napi-sys/dyn-symbols"] # Add a runtime Node version detection node_version_detect = [] tracing = ["dep:tracing"] [dependencies] bitflags = "2" # Keep ctor&`#39`;s priority support disabled until the Apple/Zig cross-link # path stops emitting unresolved `section$end$__DATA$CTOR` references. ctor = { version = "1.0.0", default-features = false } nohash-hasher = "0.2.0" rustc-hash = "2.1.1" [dependencies.anyhow] optional = true version = "1" [dependencies.napi-sys] path = "../sys" version = "3.2.2" default-features = false [dependencies.encoding_rs] optional = true version = "0.8" [dependencies.chrono] optional = true version = "0.4" [dependencies.tracing] optional = true version = "0.1" [target.&`#39`;cfg(any(all(target_family = "wasm", tokio_unstable), not(target_family = "wasm")))&`#39`;.dependencies] tokio = { version = "1", features = [ "rt", "rt-multi-thread", "sync", ], optional = true } [target.&`#39`;cfg(all(target_family = "wasm", not(tokio_unstable)))&`#39`;.dependencies] tokio = { version = "1", features = ["rt", …[truncated] <title>Getting started – NAPI-RS</title> https://napi.rs/docs/introduction/getting-started Getting started – NAPI-RS On This Page - Prerequisites - Create a project - Install, build, and test - Deep dive - How the generated package is distributed - Start directly from a template - Next steps # # Getting started The quickest way to start a napi-rs v3 package is `napi new`. It copies the maintained package template, applies your package name and target selection, and optionally creates a GitHub Actions workflow. ## # Prerequisites - Node.js for the `@napi-rs/cli` toolchain. The minimum supported versions are `^20.17.0 || ^22.13.0 || >=23.5.0` (the `engines` field of the CLI). Node.js 22.13+ on the Node 22 LTS line, or Node.js 24+, is recommended. This build-time requirement is separate from the runtime requirement of the addon you produce. See Support and compatibility. - Rust 1.88 or newer, including Cargo. Installing Rust through rustup is recommended. - Git, because `napi new` downloads and updates its template with Git. - A working linker for your development platform: Xcode Command Line Tools on macOS, MSVC Build Tools on Windows, or the usual C build tools on Linux. Node-API makes a native binary ABI-compatible with later Node.js releases that provide the Node-API level it was compiled against. That is different from the Node versions and target triples exercised by napi-rs CI. Read Support and compatibility before choosing a runtime or shipping matrix. ## # Create a project You do not need a global CLI installation. Run the package directly with your preferred package runner: ``` npx `@napi-rs/cli` new cool ``` ``` yarn dlx `@napi-rs/cli` new cool ``` ``` pnpm dlx `@napi-rs/cli` new cool --package-manager pnpm ``` The command is interactive by default. It asks for: 1. The package name written to `package.json`. 2. The minimum Node-API level used for the generated Cargo feature and package Node.js engine requirement. 3. The target triples to keep from the selected template. 4. The license. 5. Whether to generate TypeScript declarations. 6. Whether to keep the template&`#39`;s GitHub Actions workflow. Only the maintained Yarn and pnpm templates are supported. The template pins its own package-manager version, so use the matching commands after the project is created. To create a project without prompts, pass every value you want to change and add `--no-interactive`; see `napi new`. ## # Install, build, and test Inside the new project, install dependencies, then build and test: ``` cd cool yarn install yarn build yarn test ``` ``` cd cool pnpm install pnpm build pnpm test ``` The local build compiles one native target: your host unless you pass `--target`. It produces: - `..node`, the native addon. - `index.js`, the generated loader. - `index.d.ts`, the generated TypeScript declarations when type generation is enabled. The important source files in the generated project are: | Path | Purpose | | --- | --- | | `src/lib.rs` | Rust functions, structs, and classes exported with `#[napi]` | | `Cargo.toml` | Rust crate metadata and napi-rs dependencies | | `build.rs` | Required napi-rs build setup | | `package.json` | JavaScript scripts, package metadata, and the `napi` config | | `.github/workflows/CI.yml` | Multi-target build, test, artifact, and publish workflow | The templates do not check in `npm/`. The publish job creates its per-target package directories with `napi create-npm-dirs` after the platform builds. Continue with A simple package to edit the Rust API and call it from Node.js. ### # How the generated package is distributed napi-rs normally publishes a small root package plus one optional package per platform. For example, `@cool/core` might depend on: ``` { "optionalDependencies": { "`@cool/core-darwin-x64`": "1.0.0", "`@cool/core-win32-x64-msvc`": "1.0.0", "`@cool/core-linux-arm64-gnu`": "1.0.0" } } ``` The generated `index.js` first looks for a local addon produced during development. In an installed package, it loads the optional p…[truncated] <title>napi 3.10.5 - Docs.rs</title> https://docs.rs/crate/napi/latest/features napi 3.10.5 - Docs.rs # napi 3.10.5 N-API bindings - Crate - Source - Builds - Feature flags Documentation - Feature flags - default - dyn-symbols - napi4 - napi3 - napi2 - napi1 - anyhow - async - chrono - chrono_date - compat-mode - deferred_trace - encoding_rs - error_anyhow - experimental - full - futures-core - indexmap - latin1 - napi10 - napi5 - napi6 - napi7 - napi8 - napi9 - node_version_detect - noop - object_indexmap - serde - serde-json - serde-json-ordered - serde_json - tokio - tokio-stream - tokio_fs - tokio_full - tokio_io_std - tokio_io_util - tokio_macros - tokio_net - tokio_process - tokio_rt - tokio_signal - tokio_sync - tokio_test_util - tokio_time - tracing - web_stream # napi There is very little structured metadata to build this page from currently. You should check the main library docs, readme, or Cargo.toml in case the author documented the features in them. This version has 47 feature flags, 5 of them enabled by default. ### default - dyn-symbols (default) - napi4 (default) ### dyn-symbols (default) - napi-sys/ dyn-symbols(default) ### napi4 (default) - napi-sys/ napi4(default) - napi3 (default) ### napi3 (default) - napi-sys/ napi3(default) - napi2 (default) ### napi2 (default) - napi-sys/ napi2(default) - napi1 (default) ### napi1 (default) This feature flag does not enable additional features. ### anyhow - dep: anyhow ### async - tokio_rt ### chrono - dep: chrono ### chrono_date - chrono - napi5 ### compat-mode This feature flag does not enable additional features. ### deferred_trace - napi4 (default) ### encoding_rs - dep: encoding_rs ### error_anyhow - anyhow ### experimental - napi-sys/ experimental ### full - async - chrono_date - experimental - latin1 - napi10 - serde-json ### futures-core - dep: futures-core ### indexmap - dep: indexmap ### latin1 - encoding_rs ### napi10 - napi-sys/ napi10 - napi9 ### napi5 - napi-sys/ napi5 - napi4 (default) ### napi6 - napi-sys/ napi6 - napi5 ### napi7 - napi-sys/ napi7 - napi6 ### napi8 - napi-sys/ napi8 - napi7 ### napi9 - napi-sys/ napi9 - napi8 ### node_version_detect This feature flag does not enable additional features. ### noop This feature flag does not enable additional features. ### object_indexmap - indexmap ### serde - dep: serde ### serde-json - serde - serde_json ### serde-json-ordered - serde-json - serde_json/ preserve_order ### serde_json - dep: serde_json ### tokio - dep: tokio ### tokio-stream - dep: tokio-stream ### tokio_fs - tokio/ fs ### tokio_full - tokio/ full ### tokio_io_std - tokio/ io-std ### tokio_io_util - tokio/ io-util ### tokio_macros - tokio/ macros ### tokio_net - tokio/ net ### tokio_process - tokio/ process ### tokio_rt - napi4 (default) - tokio ### tokio_signal - tokio/ signal ### tokio_sync - tokio/ sync ### tokio_test_util - tokio/ test-util ### tokio_time - tokio/ time ### tracing - dep: tracing ### web_stream - futures-core - napi4 (default) - tokio-stream - tokio_rt <title>Env – NAPI-RS</title> https://napi.rs/docs/concepts/env ### `get_napi_version` ... Gets the N-API version (`process.versions.napi`). ... ```rust pub fn get_napi_version(&self) -> Result<u32> ... ### `get_node_version` ... Gets the Node.js version information. ... ```rust pub fn get_node_version(&self) -> Result<NodeVersion> ... Requires `tokio_rt` and `napi4` feature. ... Spawns a Rust future and returns a JavaScript Promise. ... ```rust pub fn spawn_ ... < T: &`#39`;static + Send + ToNapiValue, ... : &`#39`;static + Send + Future< ... = Result<T>>, ... , fut: F ... Requires `tokio_rt` and `napi4` feature.

Citations:


Set the Node.js engine floor to ">= 10.16.0". The napi4 feature requires Node-API 4, which Node.js provides from 10.16.0 onward. No inspected addon code or dependency selects a newer Node-API level, so ">= 20" is not required, and switching to napi3 is unnecessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Relax engines.node from >= 20 to >= 10 (N-API 3 runtime compatibility)

1 participant