New Jul 16, 2026

Automating ESLint migrations with Codemod

Libraries, Frameworks, etc. All from ESLint Blog View Automating ESLint migrations with Codemod on eslint.org

We are excited to announce a partnership between ESLint and Codemod to create a better migration experience for ESLint users, starting with the ESLint v8 to v9 and v9 to v10 migrations. All official ESLint codemods live in eslint/codemods and on the Codemod Registry. Community members are encouraged to open issues for missing codemods or contribute new ones through pull requests. Once reviewed and merged by maintainers, codemods are automatically published to the Codemod Registry through GitHub Actions.

What is Codemod?

Codemod is an open source platform for building, sharing, and running automated code migrations at scale. It is an OpenJS Foundation partner, and its tooling has been adopted by projects such as React, Node.js, Express, React Router, Nuxt.js, pnpm, Webpack, MSW, i18next, and more.

Its platform includes JSSG (JS ast-grep), a codemod runtime and workflow engine that supports multi-step transformations and combines deterministic, compiler-aware transformations with AI-powered steps to deliver the right balance of reliability, efficiency, and flexibility. The source code for the Codemod CLI and engine is available on GitHub.

Key features of Codemod include:

Check out the Codemod docs to learn more about JSSG (JS ast-grep), Codemod’s open source toolkit for building codemods, and explore its features.

ESLint v8 to v9 migration

For v8 to v9 migration, we’ve released two codemods: one to help upgrade ESLint config, and another for custom rules.

Migrating configuration with @eslint/v8-to-v9-config

npx codemod @eslint/v8-to-v9-config

Unlike the original ESLint Configuration Migrator, this codemod runs as a workspace migration. It can:

For JavaScript config files, the codemod works from the AST and can resolve simple bindings such as const values, identifiers, and spreads. More advanced logic, such as functions, conditionals, and dynamic require() calls, still needs manual review. The workflow also supports options such as --target, eslintConfigCustomName, and codeFormattingCommandEnabled, and prompts you to install required packages after it runs.

The codemod does not migrate --ext CLI usage, so you still need to create a config entry for the file extensions you previously passed on the command line. Learn more on @eslint/v8-to-v9-config’s registry page and in the configuration migration guide.

Migrating custom rules with @eslint/v8-to-v9-custom-rules

npx codemod @eslint/v8-to-v9-custom-rules

Important: Run this codemod only in directories containing ESLint rule files. It may incorrectly transform other JavaScript files that export functions.

The codemod supports CommonJS (module.exports = function (context) { ... }), ES Modules (export default function (context) { ... }), indirect exports (function rule() {} and module.exports = rule), higher-order wrappers such as wrapRule(function (context) { ... }), and rules created with @typescript-eslint/utils RuleCreator.

It performs a comprehensive migration of custom ESLint rules from v8 to v9, including:

The codemod also moves module.exports.schema into meta, converts old-style context.report(node, message) calls to object format, detects fixable rules, and adds fixable: "code" to meta.

It does not cover context.parserOptions and context.parserPath, because those properties are not removed until ESLint v10.0.0. Prefer context.languageOptions (and context.languageOptions.parser when you need the parser) instead.

Not every change can be fully automated. After running the codemod:

  1. Review TODO comments. Search for TODO in your migrated files. If a rule uses context.options, the codemod may leave a placeholder like schema: [] // TODO: Define schema - this rule uses context.options that you need to replace with a valid JSON schema.
  2. Review comment method changes. getCommentsBefore(), getCommentsInside(), and getCommentsAfter() require a node argument, and no-argument context.getComments() calls should use sourceCode.getAllComments().
  3. Review skipped higher-order wrappers. If a wrapper passes configuration as the second argument (for example, wrapRule(rule, config)), confirm whether any manual migration is needed.
  4. Test your custom rules by running your rule test suite (for example, npm test).

Learn more on @eslint/v8-to-v9-custom-rules’s registry page. For the full list of API changes and how to adopt them manually, see the ESLint v9 migration guide and the blog post for v9 custom rules.

ESLint v9 to v10 migration

Upgrade your ESLint project from v9 to v10 with the following codemod:

npx codemod @eslint/v9-to-v10

This recipe includes four individual codemods, each of which can also be run independently:

Check out Codemod Registry to learn more about this recipe and its codemods. For more details about what’s new in v10 and how to adopt the new features, refer to the official ESLint upgrade guide.

Conclusion

Upgrading across major ESLint versions has often meant carefully translating configs, custom rules, and related APIs by hand. With this partnership, official Codemod workflows give you a faster starting point for the v8 to v9 and v9 to v10 migrations, while still leaving room for the manual review steps that complex projects need.

You can try the codemods today through the Codemod Registry, and find the source in eslint/codemods. If you run into a gap, open an issue or contribute a new codemod. For questions about the migrations themselves, see the v9 and v10 upgrade guides, or stop by Discord to talk with the team.

Scroll to top