ESLint 9 Upgrade: Migration Guide and Benefits
Overview
This document details the changes made to upgrade the MIJUG .NET Workspace from ESLint 8 to ESLint 9, the benefits of the new version, and generic migration steps for similar projects. It also covers the new ESM globals behavior in Node.js 20+ and how to handle them for maximum compatibility and clarity.
Why Upgrade to ESLint 9?
- Performance: ESLint 9 introduces a new flat config system, improving linting speed and memory usage.
- Modern Syntax: Full ES module (ESM) support, aligning with modern JavaScript/TypeScript best practices.
- Zero-Warning Enforcement: Enhanced rule strictness and better error reporting.
- Improved Plugin Ecosystem: Updated plugin APIs and compatibility with the latest TypeScript and JavaScript features.
- Better IDE Integration: Faster and more accurate linting in VS Code and other editors.
ESM Globals in Node.js 20+
With Node.js 20 and later, the ESM (ECMAScript Module) environment now provides __dirname
and __filename
as globals, just like CommonJS. This means:
- You no longer need to polyfill or manually define
__dirname
or__filename
in most scripts. - Redeclaring these globals will cause lint errors (e.g.,
no-redeclare
). - For maximum compatibility, always use the global
__dirname
and avoid any redeclaration or fallback logic unless you must support older Node.js versions.
Example:
// Good (Node.js 20+ ESM)
const PROJECT_ROOT = path.resolve(__dirname, '..');
// Bad (causes redeclaration error)
const __dirname = path.dirname(new URL(import.meta.url).pathname);
If you must support older Node.js versions, use a conditional global assignment, but for modern projects, prefer the global.
Key Changes Applied
- Upgraded
eslint
and related plugins to version 9.x inpackage.json
. - Migrated configuration to the new flat config system (
eslint.config.js
). - Updated all custom scripts and code to use ESM import/export syntax.
- Removed all CommonJS
require()
andmodule.exports
patterns. - Fixed all lint errors and warnings, including ESM-specific issues (e.g.,
__dirname
/__filename
handling). - Ensured all scripts in
scripts/
are ESM-compatible and pass lint checks. - Updated precheckin and CI scripts to enforce zero-warning policy.
Generic Migration Steps
-
Upgrade ESLint and Plugins:
- Update
eslint
and all plugins to the latest 9.x versions inpackage.json
.
- Update
-
Migrate to Flat Config:
- Replace
.eslintrc.*
witheslint.config.js
using the flat config format.
- Replace
-
Update ESM Syntax:
- Refactor all scripts and config files to use
import
/export
. - Remove CommonJS patterns and use the new ESM globals for
__dirname
/__filename
.
- Refactor all scripts and config files to use
-
Fix Lint Errors:
- Run
eslint . --fix
and resolve all errors and warnings.
- Run
-
Update CI/Precommit:
- Ensure all linting steps in CI and precommit hooks use the new config and pass with zero warnings.
Official Documentation
Official Documentation:
- ESLint 9 Release Notes
- Use ESLint in Your Project
- Flat Config Reference
- ESLint ESM Support
- ESLint Plugin Migration
-
Jump to ESM Globals in Node.js 20+
Bibliography & Further Reading
Bibliography & Further Reading:
- ESLint 9 Release Notes — Comprehensive release notes and upgrade information for each version.
- Use ESLint in Your Project — Official documentation for configuration, migration, and usage.
- Flat Config Reference — Official documentation for the new flat config system.
- ESLint ESM Support — Details on ESM support and globals in ESLint.
- ESLint Plugin Migration — Guide for updating and using plugins with ESLint 9.
- The rel Attribute in HTML Links: A Comprehensive Guide — MIJUG documentation on secure and accessible link attributes.
- See Key Changes Applied
Last updated: August 24, 2025