ESLint v9.0.0 released

We just pushed ESLint v9.0.0, which is a major release upgrade of ESLint. This release adds some new features and fixes several bugs found in the previous release. This release also has some breaking changes, so please read the following closely.


This is a summary of the significant changes, both breaking and non-breaking, you need to know about when upgrading from ESLint v8.x to ESLint v9.0.0.


Because this is a major release, you may not automatically be upgraded by npm. To ensure you are using this version, run:

npm i eslint@9.0.0 --save-dev

Migration Guide

As there are a lot of changes, we’ve created a migration guide describing the breaking changes in great detail along with the steps you should take to address them. We expect that most users should be able to upgrade without any build changes, but the migration guide should be a useful resource if you encounter problems.

Node.js < v18.18.0, v19 no longer supported

As of this post, Node.js v20.x is the LTS release, and as such we are dropping support for all versions of Node.js prior to v18.18.0 as well as v19.x.

Flat config is now the default and has some changes

Flat config is now the default configuration format for ESLint and eslintrc is officially deprecated. To continue using a eslintrc configuration file, you’ll need to set the ESLINT_USE_FLAT_CONFIG environment variable to false.

This change affects users, plugin developers, and integrators as many aspects of ESLint had to change to make this happen. Please see our previous blog post for more details.

This release also introduces the config inspector, which can be launched on the command line using --inspect-config.

Removed all formatters except stylish, html, json, and json-with-meta

The following formatters have been removed:

  • checkstyle
  • compact
  • jslint-xml
  • junit
  • tap
  • unix
  • visualstudio

If you are using these formatters currently, you’ll need to install the standalone packages for use with ESLint v9.0.0.

Removed valid-jsdoc and require-jsdoc rules

We have removed valid-jsdoc and require-jsdoc. We recommend using the eslint-plugin-jsdoc plugin instead.

Removed deprecated methods on context and SourceCode

As we announced in September, we have removed a lot of deprecated methods from context and replaced them with methods on SourceCode.

Updated eslint:recommended

The eslint:recommended configuration is updated to include new rules that we feel are important, and to remove deprecated and less important rules.

New rule: no-useless-assignment

ESLint v9.0.0 introduces a new rule, no-useless-assignment, that is designed to catch situations where you’ve assigned a value to a variable and that value is never used. For example:

let id = 1234;      // 1234 is never used
id = calculateId();

Updates to existing rules

  • The complexity rule now also takes into account optional chaining and default values in destructuring patterns and parameters.
  • The no-fallthrough rule has a new option reportUnusedFallthroughComment.
  • The no-inner-declarations rule has a new default behavior. In v8.x, the rule would flag any functions defined inside of blocks as errors because this behavior was undefined in early versions of JavaScript. As of ES 2015, block-scoped function declarations are well-defined and so we changed the default behavior to not warn on block-scoped functions.
  • The no-misleading-character-class rule now highlights the offending characters in a regular expression rather than the entire regular expression.
  • The no-restricted-imports rule changed the behavior of paths. In v8.x, if multiple entries in the paths array of your configuration for The no-restricted-imports rule had the same name property, only the last one would apply. In v9.0.0, all entries apply, allowing for specifying different error messages for different imported names.
  • The no-restricted-imports rule has new options allowImportNames and allowImportNamePattern.
  • The no-unused-vars rule varsIgnorePattern option no longer applies to caught error variables.
  • The no-unused-vars rule has a new default value for the caughtErrors option (changed from "none" to "all").
  • The no-unused-vars rule has a new option ignoreClassWithStaticInitBlock.
  • The no-unused-vars rule has a new option reportUsedIgnorePattern.
  • The no-useless-computed-key rule has a new default value for the enforceForClassMembers option (changed from false to true). This is intended to help avoiding misleading comments that can occur as a result of refactoring. When this option is set to true, the rule will prohibit a fallthrough comment if a case can never fallthrough.

New API loadESLint()

ESLint now exports a new function loadESLint() from its main entry point. Integrations can use this function to get either the ESLint class (former FlatESLint class) or the LegacyESLint class (former ESLint class) and thus easily swap between flat config and eslintrc APIs.

Changes to how you write rules

We’ve made multiple changes to help prevent errors in rules:

  1. Function-style rules will stop working in v9.0.0. Function-style rules are rules created by exporting a function from a file rather than exporting an object with a create() method.
  2. When a rule doesn’t have meta.schema specified, a default schema of [] will be applied. This means that rules without a schema will be assumed to have no options, which in turn means that validation will fail if options are provided.

Stricter RuleTester validations

This release adds more checks in RuleTester:

  • Messages cannot have unsubstituted placeholders.
  • Suggestions must change the code.
  • Suggestion messages must be unique for the same lint problem.
  • Suggestions must generate valid syntax.
  • Test case output must be different from code.
  • Test error objects must specify message or messageId.
  • Test error object must specify suggestions if the actual error provides suggestions.
  • Test suggestion objects must specify desc or messageId.
  • Test suggestion objects must specify output.
  • filename and only properties of test objects must be of the expected type (string and boolean, respectively).
  • Duplicate tests cause an error.

The --output-file flag now guarantees a file is output

The --output-file CLI flag is designed to output the results of the ESLint run to specified file. Prior to this release, no file would be output if linting passed with no errors or warnings. In v9.0.0, an empty file will be output when linting passes without any errors or warnings.

Better scope analysis

In v9.0.0, we updated the behavior of eslint-scope to fix a couple of longstanding bugs:

  1. Previously, ESLint would treat ("use strict") as a strict mode directive even though it is not. We fixed the behavior so only valid strict mode directives are honored.
  2. The containing scope of a class extends clause was incorrectly set to be the scope containing the class when it should have been the class scope itself. This has been fixed.

CodePath#currentSegments removed

As announced in our previous post, CodePath#currentSegments has been removed from the rules API. Please refer to the post for more details.

Precalculated Code Paths

ESLint v9.0.0 now precalculates code path information before the traversal used by rules. As a result, the code path information is now complete regardless of where it is accessed inside of a rule.

Multiple /* eslint */ comments for the same rule are now disallowed

In ESLint v8.x, if the file being linted contained multiple /* eslint */ configuration comments for the same rule, the last one would be applied, while the others would be silently ignored.

In ESLint v9.0.0, the first one is applied, while the others are reported as lint errors.

--quiet option is more performant

The --quiet option hides all warnings in the ESLint console. In v9.0.0, we are making a performance improvement by also not executing any rules set to "warn".

Running eslint with no file arguments

If you are using flat config and you don’t pass any file arguments to the CLI, the CLI will default to linting the current directory, which means you can type npx eslint and it will just work. (Doing the same with an eslintrc config file will result in an error.)

Unused disable directives cause warnings by default

ESLint has long been able to flag unused disable directives. In this release, we’ve enabled warnings for unused disable directives by default. You can modify this value in your config file with linterOptions.reportUnusedDisableDirectives or on the command line using --report-unused-disable-directives-severity.

Performance statistics available in formatters via --stats

The information from the rule profiler is now available inside of formatters when the --stats flag is used in the CLI. This allows anyone to create custom visualizations of the performance information that ESLint tracks.

Breaking Changes


Bug Fixes


  • e151050 docs: update get-started to the new @eslint/create-config (#18217) (唯然)
  • 94178ad docs: mention about name field in flat config (#18252) (Anthony Fu)
  • 1765c24 docs: add Troubleshooting page (#18181) (Josh Goldberg ✨)
  • 96607d0 docs: version selectors synchronization (#18260) (Milos Djermanovic)
  • 651ec91 docs: remove /* eslint-env */ comments from rule examples (#18249) (Milos Djermanovic)
  • 950c4f1 docs: Update README (GitHub Actions Bot)
  • 12f5746 docs: add info about dot files and dir in flat config (#18239) (Tanuj Kanti)
  • b93f408 docs: update shared settings example (#18251) (Tanuj Kanti)
  • 26384d3 docs: fix ecmaVersion in one example, add checks (#18241) (Milos Djermanovic)
  • 7747097 docs: Update PR review process (#18233) (Nicholas C. Zakas)
  • b07d427 docs: fix typo (#18246) (Kirill Gavrilov)
  • 778082d docs: add Glossary page (#18187) (Josh Goldberg ✨)
  • 239a7e2 docs: Clarify the description of sort-imports options (#18198) (gyeongwoo park)
  • 4769c86 docs: fix incorrect example in no-lone-blocks (#18215) (Tanuj Kanti)
  • 5251327 docs: Update README (GitHub Actions Bot)
  • 1dc8618 docs: Update README (GitHub Actions Bot)
  • ba1c1bb docs: Update README (GitHub Actions Bot)
  • 337cdf9 docs: Explain limitations of RuleTester fix testing (#18175) (Nicholas C. Zakas)
  • c7abd89 docs: Explain Node.js version support (#18176) (Nicholas C. Zakas)
  • d961eeb docs: show red underlines in examples in rules docs (#18041) (Yosuke Ota)
  • 558274a docs: Update README (GitHub Actions Bot)
  • 2908b9b docs: Update release documentation (#18174) (Nicholas C. Zakas)
  • 1f1260e docs: replace HackerOne link with GitHub advisory (#18165) (Francesco Trotta)
  • e5ef3cd docs: add inline cases condition in no-fallthrough (#18158) (Tanuj Kanti)
  • 450d0f0 docs: fix ignore option docs (#18154) (Francesco Trotta)
  • 5fe095c docs: show v8.57.0 as latest version in dropdown (#18142) (Milos Djermanovic)
  • 7db5bb2 docs: Show prerelease version in dropdown (#18135) (Nicholas C. Zakas)
  • 73a5f06 docs: Update README (GitHub Actions Bot)
  • f95cd27 docs: Disallow multiple rule configuration comments in the same example (#18116) (Milos Djermanovic)
  • d8068ec docs: Update link for schema examples (#18112) (Svetlana)
  • f1c7e6f docs: Switch to Ethical Ads (#18090) (Strek)
  • 15c143f docs: JS Foundation -> OpenJS Foundation in PR template (#18092) (Nicholas C. Zakas)
  • 6ea339e docs: add stricter rule test validations to v9 migration guide (#18085) (Milos Djermanovic)
  • 3c816f1 docs: use relative link from CLI to core concepts (#18083) (Milos Djermanovic)
  • 9458735 docs: fix malformed eslint config comments in rule examples (#18078) (Francesco Trotta)
  • 07a1ada docs: link from --fix CLI doc to the relevant core concept (#18080) (Bryan Mishkin)
  • b844324 docs: Update team responsibilities (#18048) (Nicholas C. Zakas)
  • aadfb60 docs: document languageOptions and other v9 changes for context (#18074) (fnx)
  • 857e242 docs: tweak explanation for rule properties (#18057) (Bryan Mishkin)
  • 10485e8 docs: recommend messageId over message for reporting rule violations (#18050) (Bryan Mishkin)
  • 98b5ab4 docs: Update README (GitHub Actions Bot)
  • 505fbf4 docs: update no-restricted-imports rule (#18015) (Tanuj Kanti)
  • c25b4af docs: Update README (GitHub Actions Bot)
  • 33d1ab0 docs: add more examples to flat config ignores docs (#18020) (Milos Djermanovic)
  • e6eebca docs: Update sort-keys options properties count (#18025) (LB (Ben Johnston))
  • 1fedfd2 docs: Improve flat config ignores docs (#17997) (Nicholas C. Zakas)
  • 38b9b06 docs: update valid-typeof rule (#18001) (Tanuj Kanti)
  • b4abfea docs: Update note about ECMAScript support (#17991) (Francesco Trotta)
  • 6788873 docs: Update release blog post template (#17994) (Nicholas C. Zakas)
  • 1f37442 docs: Add sections on non-npm plugin configuration (#17984) (Nicholas C. Zakas)
  • 96307da docs: migration guide entry for no-inner-declarations (#17977) (Tanuj Kanti)
  • 40be60e docs: Update README (GitHub Actions Bot)
  • d31c180 docs: fix number of code-path events on custom rules page (#17969) (Richard Hunter)
  • 1529ab2 docs: reorder entries in v9 migration guide (#17967) (Milos Djermanovic)
  • 9507525 docs: Explain how to combine configs (#17947) (Nicholas C. Zakas)
  • 7c78576 docs: Add more removed context methods to migrate to v9 guide (#17951) (Milos Djermanovic)
  • 3a877d6 docs: Update removed CLI flags migration (#17939) (Nicholas C. Zakas)
  • 4a9cd1e docs: Update Linter API for v9 (#17937) (Milos Djermanovic)
  • 2a8eea8 docs: update docs for v9.0.0-alpha.0 (#17929) (Milos Djermanovic)
  • 7f0ba51 docs: show NEXT in version selectors (#17911) (Milos Djermanovic)
  • 0a7911e docs: add flat config default to v9 migration guide (#17927) (Milos Djermanovic)
  • 94f8065 docs: Add CLI updates to migrate to v9 guide (#17924) (Nicholas C. Zakas)
  • 16187f2 docs: Add exported and string config notes to migrate to v9 guide (#17926) (Nicholas C. Zakas)
  • 3ae50cc docs: Add RuleTester changes to migrate to v9 guide (#17923) (Nicholas C. Zakas)
  • 0831b58 docs: add rule changes to v9 migration guide (#17925) (Milos Djermanovic)
  • 037abfc docs: update API docs (#17919) (Milos Djermanovic)
  • afc3c03 docs: add function-style and meta.schema changes to v9 migration guide (#17912) (Milos Djermanovic)
  • 1da0723 docs: update eslint:recommended section in Migrate to v9.x (#17908) (Milos Djermanovic)
  • f55881f docs: remove (#17907) (Milos Djermanovic)
  • 63ae191 docs: Migrate to v9.0.0 (#17905) (Nicholas C. Zakas)
  • e708496 docs: Switch to flat config by default (#17840) (Nicholas C. Zakas)
  • fdf0424 docs: Update Create a Plugin for flat config (#17826) (Nicholas C. Zakas)
  • e6a91bd docs: Switch shareable config docs to use flat config (#17827) (Nicholas C. Zakas)
  • 3831fb7 docs: updated examples of max-lines rule (#17898) (Tanuj Kanti)
  • cd1ac20 docs: Update README (GitHub Actions Bot)
  • 26010c2 Build: changelog update for 9.0.0-rc.0 (Jenkins)
  • b91f9dc build: fix TypeError in prism-eslint-hooks.js (#18209) (Francesco Trotta)
  • d7ec0d1 Build: changelog update for 9.0.0-beta.2 (Jenkins)
  • fd9c0a9 Build: changelog update for 9.0.0-beta.1 (Jenkins)
  • c9f2f33 build: changelog update for 8.57.0 (#18144) (Milos Djermanovic)
  • 1bbc495 Build: changelog update for 9.0.0-beta.0 (Jenkins)
  • 96f8877 Build: changelog update for 9.0.0-alpha.2 (Jenkins)
  • 52d5e7a Build: changelog update for 9.0.0-alpha.1 (Jenkins)
  • c2bf27d build: update docs files when publishing prereleases (#17940) (Milos Djermanovic)
  • e91d85d Build: changelog update for 9.0.0-alpha.0 (Jenkins)


  • 19f9a89 chore: Update dependencies for v9.0.0 (#18275) (Nicholas C. Zakas)
  • 7c957f2 chore: package.json update for @eslint/js release (Jenkins)
  • d73a33c chore: ignore /docs/v8.x in link checker (#18274) (Milos Djermanovic)
  • 44a81c6 chore: upgrade knip (#18272) (Lars Kappert)
  • e80b60c chore: remove code for testing version selectors (#18266) (Milos Djermanovic)
  • a98babc chore: add npm script to run WebdriverIO test (#18238) (Francesco Trotta)
  • 9b7bd3b chore: update dependency markdownlint to ^0.34.0 (#18237) (renovate[bot])
  • 297416d chore: package.json update for eslint-9.0.0-rc.0 (#18223) (Francesco Trotta)
  • d363c51 chore: package.json update for @eslint/js release (Jenkins)
  • 1b841bb chore: fix some comments (#18213) (avoidaway)
  • 29c3595 chore: remove repetitive words (#18193) (cuithon)
  • acc2e06 chore: Introduce Knip (#18005) (Lars Kappert)
  • 7509276 chore: upgrade @eslint/js@9.0.0-beta.2 (#18180) (Milos Djermanovic)
  • 96087b3 chore: package.json update for @eslint/js release (Jenkins)
  • 925afa2 chore: Remove some uses of lodash.merge (#18179) (Milos Djermanovic)
  • 972ef15 chore: remove invalid type in @eslint/js (#18164) (Nitin Kumar)
  • 32ffdd1 chore: upgrade @eslint/js@9.0.0-beta.1 (#18146) (Milos Djermanovic)
  • e41425b chore: package.json update for @eslint/js release (Jenkins)
  • bb3b9c6 chore: upgrade @eslint/eslintrc@3.0.2 (#18145) (Milos Djermanovic)
  • e462524 chore: upgrade eslint-release@3.2.2 (#18138) (Milos Djermanovic)
  • 8e13a6b chore: fix spelling mistake in (#18128) (Will Eastcott)
  • 66f52e2 chore: remove unused tools rule-types.json, update-rule-types.js (#18125) (Josh Goldberg ✨)
  • bf0c7ef ci: fix sync-labels value of pr-labeler (#18124) (Tanuj Kanti)
  • cace6d0 ci: add PR labeler action (#18109) (Nitin Kumar)
  • 1a65d3e chore: export base config from eslint-config-eslint (#18119) (Milos Djermanovic)
  • 9aa4df3 refactor: remove globals dependency (#18115) (Milos Djermanovic)
  • e40d1d7 chore: upgrade @eslint/js@9.0.0-beta.0 (#18108) (Milos Djermanovic)
  • 9870f93 chore: package.json update for @eslint/js release (Jenkins)
  • 2c62e79 chore: upgrade @eslint/eslintrc@3.0.1 (#18107) (Milos Djermanovic)
  • 81f0294 chore: upgrade espree@10.0.1 (#18106) (Milos Djermanovic)
  • 5e2b292 chore: upgrade eslint-visitor-keys@4.0.0 (#18105) (Milos Djermanovic)
  • ce838ad chore: replace dependency npm-run-all with npm-run-all2 ^5.0.0 (#18045) (renovate[bot])
  • 54df731 chore: update dependency markdownlint-cli to ^0.39.0 (#18084) (renovate[bot])
  • 8f06a60 chore: update dependency shelljs to ^0.8.5 (#18079) (Francesco Trotta)
  • 93ffe30 chore: update dependency file-entry-cache to v8 (#17903) (renovate[bot])
  • 6ffdcbb chore: upgrade @eslint/js@9.0.0-alpha.2 (#18038) (Milos Djermanovic)
  • 2c12715 chore: package.json update for @eslint/js release (Jenkins)
  • cc74c4d chore: upgrade espree@10.0.0 (#18037) (Milos Djermanovic)
  • dfb68b6 chore: use Node.js 20 for docs sites (#18026) (Milos Djermanovic)
  • 8c1b8dd test: add more tests for ignoring files and directories (#18018) (Milos Djermanovic)
  • 60b966b chore: update dependency @eslint/js to v9.0.0-alpha.1 (#18014) (renovate[bot])
  • c893bc0 chore: update markdownlint to v0.33.0 (#17995) (Nitin Kumar)
  • c5e50ee chore: package.json update for @eslint/js release (Jenkins)
  • 1bf2520 chore: Split Docs CI from core CI (#17897) (Nicholas C. Zakas)
  • 320787e chore: delete relative-module-resolver.js (#17981) (Francesco Trotta)
  • 4926f33 refactor: use Object.hasOwn() (#17948) (Milos Djermanovic)
  • df200e1 refactor: use to get last elements (#17949) (Milos Djermanovic)
  • 750b8df chore: update dependency glob to v10 (#17917) (renovate[bot])
  • 74794f5 chore: removed unused eslintrc modules (#17938) (Milos Djermanovic)
  • 10ed29c chore: remove unused dependency rimraf (#17934) (Francesco Trotta)
  • 903ee60 ci: use --force flag when installing eslint (#17921) (Milos Djermanovic)
  • 17fedc1 chore: upgrade @eslint/js@9.0.0-alpha.0 (#17928) (Milos Djermanovic)
  • cb89ef3 chore: package.json update for @eslint/js release (Jenkins)
  • f6f4a45 chore: drop structuredClone polyfill for v9 (#17915) (Kevin Gibbons)
  • 412dcbb chore: upgrade eslint-plugin-n@16.6.0 (#17916) (Milos Djermanovic)
  • 02a8baf chore: Rename files with underscores (#17910) (Nicholas C. Zakas)
  • c0f5d91 chore: remove creating an unused instance of Linter in tests (#17902) (Milos Djermanovic)
  • 3826cdf chore: use jsdoc/no-multi-asterisks with allowWhitespace: true (#17900) (Percy Ma)
  • a9a17b3 chore: fix getting scope in tests (#17899) (Milos Djermanovic)
  • 595a1f6 test: ensure that CLI tests run with FlatESLint (#17884) (Francesco Trotta)
  • c7eca43 chore: update dependency markdownlint-cli to ^0.38.0 (#17865) (renovate[bot])
  • cc0c9f7 ci: bump github/codeql-action from 2 to 3 (#17873) (dependabot[bot])

The latest ESLint news, case studies, tutorials, and resources.

ESLint v9.5.0 released
2 min read

ESLint v9.5.0 released

We just pushed ESLint v9.5.0, which is a minor release upgrade of ESLint. This release adds some new features and fixes several bugs found in the previous release.

ESLint v9.4.0 released
1 min read

ESLint v9.4.0 released

We just pushed ESLint v9.4.0, which is a minor release upgrade of ESLint. This release adds some new features and fixes several bugs found in the previous release.