n/no-unsupported-features/node-builtins
Disallow Node.js APIs that the Node.js versions you support do not have
Also called node/no-unsupported-features/node-builtins
A Node.js API that's newer than the oldest version you support is missing there. An import of it fails when the file loads, and a call throws a TypeError. You only find out when somebody runs the code on that version.
The rule checks anything you take from built-in modules with import, require() or process.getBuiltinModule(), globals such as fetch, and the properties of import.meta. It takes the versions you support from engines.node in your package.json. If nothing sets a range, it assumes >=16.0.0. Every version in the range must have the API, and it must be stable there. An API that's still experimental is reported too.
Configure#
Off by default. To turn it on:
[lint.rules]
"n/no-unsupported-features/node-builtins" = "error" # or "warn"Every option, set to its default. The ones that are commented out are unset by default.
[lint.rules]
"n/no-unsupported-features/node-builtins" = ["error", {
# version = <string>,
allowExperimental = false,
ignores = [], # list of strings
}]Examples#
Reported, because util.parseArgs has been stable since 20.0.0, fetch since 21.0.0 and import.meta.dirname since 24.0.0:
import { parseArgsThe util.parseArgs is still an experimental feature and is not supported until Node.js 20.0.0. The configured version range is >=16.0.0. } from "node:util";
const { values } = parseArgs({ options: { url: { type: "string" } } });
const response = await fetchThe fetch is still an experimental feature and is not supported until Node.js 21.0.0. The configured version range is >=16.0.0.(values.url);
console.log(import.meta.dirnameThe import.meta.dirname is still an experimental feature and is not supported until Node.js 24.0.0 (backported: ^22.16.0). The configured version range is >=16.0.0.);import https from "node:https";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
https.get(process.argv[2], (response) => response.pipe(process.stdout));
console.log(dirname(fileURLToPath(import.meta.url)));With a newer engines.node, parseArgs is fine:
{
"name": "app",
"engines": { "node": ">=20.0.0" }
}import { parseArgs } from "node:util";
const { values } = parseArgs({ options: { url: { type: "string" } } });Options#
| Option | Default | What it does |
|---|---|---|
version | engines.node, or ">=16.0.0" | The range of Node.js versions you support, written as in package.json. |
allowExperimental | false | Allow an API if every version in the range has it, even as experimental. |
ignores | [] | APIs that are never reported, by the name in the message, such as "fs.cpSync" or "test". |
Without version, the range comes from settings.n.version ([lint.settings.n] in bunfig.toml, or settings in an ESLint config), then from engines.node, then from devEngines.runtime in package.json.
[lint.rules]
"n/no-unsupported-features/node-builtins" = ["error", {
version = ">=22.5.0",
allowExperimental = true,
}]node:sqlite has been experimental since 22.5.0:
{ "version": ">=22.5.0" }1 problemimport { DatabaseSync } from "node:sqlite";The sqlite is still an experimental feature The configured version range is >=22.5.0.{ "version": ">=22.5.0", "allowExperimental": true }No problemsimport { DatabaseSync } from "node:sqlite";{ "version": ">=22.0.0", "allowExperimental": true }2 problemsimport { The sqlite is not an experimental feature until Node.js 22.5.0. The configured version range is >=22.0.0.DatabaseSyncThe sqlite is not an experimental feature until Node.js 22.5.0. The configured version range is >=22.0.0.The sqlite.DatabaseSync is still an experimental feature and is not supported until Node.js 22.5.0. The configured version range is >=22.0.0. } from "node:sqlite";{ "ignores": ["fs.cpSync"] }No problemsimport fs from "node:fs";
fs.cpSync("public", "dist", { recursive: true });When not to use it#
If the code never runs in Node.js, for example because it only runs in Bun, the reports don't apply.