n/no-unsupported-features/es-syntax

Disallow JavaScript syntax that the Node.js versions you support do not have

Also called node/no-unsupported-features/es-syntax

Syntax that's newer than the oldest Node.js you support is a SyntaxError there, so the file doesn't load at all. You only find out when somebody runs it on that version.

The rule 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 feature.

Besides syntax, it reports newer built-ins such as Object.hasOwn, and newer methods such as .at() when the code shows they're called on an array or a string.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"n/no-unsupported-features/es-syntax" = "error" # or "warn"

Every option, set to its default. The ones that are commented out are unset by default.

bunfig.toml
[lint.rules]
"n/no-unsupported-features/es-syntax" = ["error", {
  # version = <string>,
  ignores = [], # list of strings
}]

Examples#

Reported, because Node.js has had static blocks since 16.11.0 and the v flag since 20.0.0:

example.js2 problems
class Cache {
  static instance;
  static {
    Cache.instance = new Cache();
  }
}

const word = /[\p{L}--[a-z]]/v;
example.jsNo problems
class Cache {
  static instance = new Cache();
}

const word = /\p{L}/u;

With a newer engines.node, static blocks are fine:

package.json
{
  "name": "app",
  "engines": { "node": ">=18.0.0" }
}
example.jsNo problems
class Cache {
  static instance;
  static {
    Cache.instance = new Cache();
  }
}

A method is reported if the rule can tell that the value is an array or a string:

example.js1 problem
const steps = ["build", "test", "publish"];
const last = steps.at(-1);
example.jsNo problems
function lastOf(steps) {
  return steps.at(-1);
}

Options#

OptionDefaultWhat it does
versionengines.node, or ">=16.0.0"The range of Node.js versions you support, written as in package.json.
ignores[]Features that are never reported, by the name in the message, such as "class-static-block".

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.

bunfig.toml
[lint.rules]
"n/no-unsupported-features/es-syntax" = ["error", {
  version = ">=14.0.0",
  ignores = ["logical-assignment-operators"],
}]
example.jswith { "version": ">=14.0.0" }1 problem
options.retries ??= 3;
example.jswith { "version": ">=15.0.0" }No problems
options.retries ??= 3;
example.jswith { "version": ">=14.0.0", "ignores": ["logical-assignment-operators"] }No problems
options.retries ??= 3;

When not to use it#

If you compile the code for the versions you target before it runs, with TypeScript or a bundler, the source can use any syntax.