ESLint
ESLint is an open-source, pluggable JavaScript linting utility that statically analyzes ECMAScript and JSX code to identify problematic patterns, enforce coding standards, and suggest fixes for potential errors, thereby enhancing code quality across browser, server, and framework environments.[1] Created by Nicholas C. Zakas in June 2013 as an extensible alternative to earlier tools like JSLint and JSHint, it uses an abstract syntax tree (AST) for evaluation and supports Node.js installation via npm, with its first major release (version 1.0.0) arriving in July 2015.[2][3]
Key to its design is a philosophy of full pluggability, where bundled and custom rules can be toggled on or off, configured as warnings or errors, and extended through plugins without promoting any specific coding style—allowing developers to tailor linting to project needs.[2] It integrates seamlessly with text editors like Visual Studio Code and continuous integration pipelines, supports modern ECMAScript versions (from ES3 to the latest stage-4 proposals), and receives biweekly updates to maintain compatibility with evolving JavaScript standards.[1][4]
As the leading JavaScript linter, ESLint boasts over 65 million weekly downloads on npm and is adopted by prominent organizations such as Microsoft, Airbnb, Netflix, and Facebook, reflecting its robust community support from 150 sponsors contributing approximately $134,000 annually (as of November 2025).[1][5][6] Its active maintenance by a technical steering committee ensures ongoing evolution, including recent advancements like version 9.39.1 released in November 2025.[4]
Introduction
Definition and Purpose
ESLint is an open-source, pluggable linting utility designed specifically for JavaScript and JSX codebases.[1] It performs static code analysis to detect problematic patterns, potential errors, and style inconsistencies, enabling developers to maintain higher code quality without runtime execution.[7] As a tool focused on early issue identification, ESLint integrates seamlessly into development workflows to enforce consistency across projects.[1]
The primary purposes of ESLint include enforcing coding standards, catching potential bugs before they propagate, and promoting the development of maintainable code in diverse environments such as browsers, servers, and frameworks like Node.js and React.[1] By highlighting violations against configurable rules, it helps teams adhere to best practices, reducing technical debt and improving overall software reliability.[7] This proactive approach has made ESLint a staple in modern JavaScript development, supporting scalable applications across client-side and server-side contexts.[1]
ESLint natively supports JavaScript adhering to ECMAScript 6 and later versions (ES6+), as well as JSX syntax for React-like components.[8] Through extensible parsers provided by plugins, it can analyze code in TypeScript or other preprocessors, broadening its applicability while maintaining a core focus on JavaScript ecosystems.[9]
Unlike compilers, which transpile source code into executable formats, or formatters like Prettier that automatically reformat code style, ESLint emphasizes linting through analysis and reporting to guide manual corrections.[7] It does not alter code structure for compatibility or aesthetics but instead provides actionable feedback to enhance readability and prevent errors.[1]
Core Principles
ESLint's foundational design revolves around pluggability, enabling users to extend its core functionality without altering the tool itself. This principle manifests through modular components such as rules, which define specific code patterns to enforce or flag; parsers, which handle various syntaxes including ECMAScript standards and extensions like TypeScript; and formatters, which output results in customizable styles. Plugins further amplify this by bundling custom rules, configurations, and processors that extract JavaScript from non-standard files, such as Markdown, ensuring ESLint remains adaptable to diverse JavaScript ecosystems without core modifications.[10]
Central to ESLint's architecture is its emphasis on customization, allowing teams to tailor linting standards to project needs and coding conventions. Users can configure rules with severity levels—off, warn, or error—and apply overrides for specific files, directories, or glob patterns, while environments define globals and parser options for contexts like browsers or Node.js. This flexibility supports heterogeneous teams by accommodating varied codebases, from legacy scripts to modern frameworks, through shareable configurations that promote consistency across projects.[10][11]
To address performance in large-scale applications, ESLint incorporates caching mechanisms that store linting results in a file, typically .eslintcache, and reuse them to process only modified files on subsequent runs, thereby reducing overhead in iterative development workflows. Recent enhancements, such as multithreaded linting introduced in version 9.34.0, leverage worker threads to parallelize file processing, significantly cutting lint times for expansive monorepos. These features ensure scalability, making ESLint suitable for enterprise-level codebases where full scans would otherwise impede productivity.[12][13]
ESLint embodies an open-source ethos, developed collaboratively under the MIT license to foster widespread accessibility and contribution. Maintained by the OpenJS Foundation, it encourages community input via GitHub, with integrations into editors, CI pipelines, and tools like Webpack, enhancing interoperability while prioritizing permissive licensing for seamless adoption in commercial and open projects.[4][1]
History
Origins and Creation
ESLint was created by Nicholas C. Zakas in June 2013 while he was working as a principal architect at Box. The project stemmed from frustrations with existing JavaScript linters such as JSLint and JSHint, which lacked the flexibility to support custom rules tailored to specific team needs.[2][14]
The initial impetus came from addressing a particular bug in a work project at Box, where a client's Internet Explorer 7 security policy blocked the native XMLHttpRequest object, necessitating an in-house Ajax wrapper function. An existing regex-based linter in the build system failed to enforce the team's requirement to use this wrapper consistently, highlighting the limitations of available tools. Zakas sought a more robust solution using an abstract syntax tree (AST) for precise code analysis, inspired by a PHP linter he encountered in Box's build process.[14]
Zakas developed the first prototype of ESLint over two weekends, leveraging open-source libraries including Esprima for parsing JavaScript into an AST, estraverse for traversing the tree, and escope for analyzing variable scopes. This approach enabled the creation of pluggable rules that could be easily extended, setting ESLint apart from its predecessors. The prototype focused on basic rule enforcement to catch patterns like incorrect function usage in the Ajax scenario.[14]
Shortly after its inception, ESLint was released as an open-source project on GitHub, with the first alpha version, v0.1.0, made publicly available on November 4, 2013. This initial release emphasized core functionality for defining and applying custom linting rules, inviting community feedback to refine the tool.[15][2]
Major Releases and Evolution
ESLint's evolution has been marked by iterative major releases that introduced foundational extensibility features, refined core mechanics, and shifted toward modern configuration paradigms. The first stable major version, v1.0.0, released on July 31, 2015, established shareable configurations, enabling developers to package and distribute reusable rule sets via npm under scoped names like @scope/eslint-config, with shortcuts for easier integration and a root: true option to prevent cascading loads from parent directories.[3] This release also updated the Espree parser for emerging language features like new.target and experimental object rest/spread properties, laying groundwork for broader syntax support.[3]
Building on this, v2.0.0 arrived on February 12, 2016, introducing plugin support that allowed extensions to export environments, globals, and even shareable configs directly, eliminating the need for separate packages and streamlining custom rule development.[16] Key enhancements included code path analysis for more precise rule execution across control flow branches and an improved --[init](/page/init) command for automated configuration based on project patterns, alongside new formatters like [table](/page/table) and visualstudio for better output handling.[16] Auto-fixing capabilities, initially limited, began expanding with support for more rules during this period, allowing --fix to automatically resolve certain issues without manual intervention.[1]
Mid-term developments continued with v3.0.0 on July 1, 2016, which mandated explicit configuration files—erroring out without one—and enhanced parser flexibility through Node.js 4+ requirements and updates to the eslint:recommended set, incorporating rules like require-yield for generators while adding fixers for rules such as prefer-const.[17] By v5.0.0, released on June 22, 2018, ESLint deprecated legacy options like experimentalObjectRestSpread in favor of standardized parser configurations, modernizing the API and making linting nonexistent files a fatal error to enforce stricter project setups.[18] These changes prioritized cleaner, more reliable integrations with evolving JavaScript environments.
Recent advancements reflect a focus on performance and simplicity. v8.0.0, launched on October 9, 2021, added full ES2022 support—including class fields, private methods, and top-level await—along with autofix for unused disable directives via --report-unused-disable-directives, though the experimental flat config system debuted later in v8.21.0 on August 1, 2022, as an opt-in alternative to the legacy .eslintrc format for array-based, file-centric setups.[19][20] This shift toward flat configs aimed at simpler, more performant configurations by reducing inheritance complexity and enabling programmatic definitions. v9.0.0, released on April 5, 2024, made flat configs the default, dropping legacy eslintrc as optional while introducing rule API updates for better language plugin compatibility, including TypeScript enhancements through improved parser options and ecosystem alignment.[21] Performance optimizations followed in the v9 series, such as multithreaded linting in v9.34.0 (August 22, 2025) and refined worker management in v9.37.0 (October 3, 2025), alongside architectural refactors like the FileReport system for reporting.[22]
As of November 3, 2025, the latest stable release is v9.39.1, primarily delivering bug fixes and minor stability improvements to the flat config implementation and auto-fixing behaviors.[23] Looking ahead, v10.0.0-alpha.0 is slated for release around November 14, 2025, previewing greater modularity by fully removing eslintrc support, updating the config lookup to file-based algorithms, and dropping Node.js versions below 20.19.0, while enabling beta JSX reference tracking and refining AST handling for enhanced extensibility.[24] Across versions, auto-fixing has matured from basic rule-specific patches to syntax-aware transformations that preserve code intent, integrated seamlessly into flat configs for faster, safer automated corrections.[1]
Features
Rules and Customization
ESLint provides over 200 built-in rules that enforce coding standards and detect potential issues in JavaScript and TypeScript code.[25] These rules are categorized into groups such as Possible Problems, which focus on preventing logic errors and syntax issues like unused variables via the no-unused-vars rule; Suggestions, which promote best practices to avoid bugs, such as prefer-const for preferring constants over let variables; and Layout & Formatting, which handle stylistic concerns like semicolon usage with the semi rule.[25] Note that Layout & Formatting rules are deprecated since ESLint v8.53.0 and recommended to be replaced with external formatters like Prettier or the @stylistic/eslint-plugin.[26] Each rule can be marked as recommended (✅), fixable (🔧 for auto-correction), a suggestion (💡), or frozen (❄️ for stable rules), allowing users to prioritize based on project needs.[25]
Customization of rules occurs through severity levels and options specified in configuration files, enabling fine-tuned enforcement. Severity levels include "off" (0, disabled), "warn" (1, issues a warning without failing the lint), and "error" (2, treats violations as errors that halt builds).[27] For example, the [semi](/page/Semi) rule can be configured as {"semi": ["error", "always"]} to require semicolons and report missing ones as errors, or with additional options like ignoring trailing semicolons in specific contexts.[27] Rules support disabling mechanisms for flexibility, such as block comments (/* eslint-disable no-unused-vars */), line-specific overrides (// eslint-disable-next-line [semi](/page/SEMI)), or file patterns in configs to exclude certain rules from test files.[27] Many rules are auto-fixable, meaning ESLint's --fix flag can automatically apply corrections, such as adding missing semicolons or converting var to const.[12]
To accommodate different environments, ESLint uses language options and globals presets that adjust rules for contexts like Node.js, browser, or ES modules. For Node.js, the node globals preset enables recognition of built-in modules like process without flagging them as undefined, paired with sourceType: "commonjs".[8] Browser environments activate the browser globals for window and document objects, while ES modules set sourceType: "module" to support import/export syntax and strict mode, ensuring rules like no-undef do not incorrectly flag module globals.[8] These presets allow environment-specific rules to run without additional configuration, enhancing compatibility across project types.[8]
Plugins and Extensibility
ESLint's extensibility is primarily achieved through plugins, which are third-party npm packages that extend its core functionality by providing additional rules, parsers, configurations, and processors tailored to specific domains or frameworks.[10] These plugins allow developers to enforce domain-specific linting, such as React component best practices or TypeScript type safety, without modifying the core ESLint codebase. Plugins are installed via npm and configured in ESLint's configuration files, enabling modular enhancements to the linter's capabilities.[28]
Custom rules form a cornerstone of plugin development, allowing users to define bespoke linting logic for unique project needs. To create a custom rule, developers export a JavaScript object from a module that includes a meta property for metadata (such as rule type, description, and fixability) and a create function returning visitor methods for traversing the abstract syntax tree (AST).[29] The create function receives a context object, which provides access to the source code, reporting mechanisms via context.report(), and AST node traversal using visitor patterns for specific node types like Identifier or FunctionDeclaration.[30] For testing, ESLint's RuleTester API is used to validate rules against valid and invalid code samples, ensuring they correctly identify issues and apply fixes where applicable.[31] This process involves AST analysis to inspect code structure, such as checking for prohibited patterns, and is exemplified in rules that enforce naming conventions or detect potential bugs through node property examination.[32]
Beyond rules, ESLint offers multiple extensibility points for deeper customization. Custom parsers enable support for non-standard JavaScript syntax by transforming source code into an AST compatible with ESLint's rules; for instance, the @typescript-eslint/parser package parses TypeScript files, while Babel's parser handles experimental ECMAScript features.[33] Developers create parsers by implementing a parse or parseForESLint method that returns the AST, often leveraging underlying libraries like Espree for base parsing.[34] Custom processors extend linting to non-JavaScript files by preprocessing text to extract embeddable JavaScript (e.g., from Markdown via @eslint/markdown) and postprocessing results to map errors back to the original file locations.[35] These processors include preprocess and postprocess functions to handle code extraction and message aggregation.[36] Additionally, custom formatters allow tailoring output styling, such as generating JSON or custom reports; they are functions that process lint results into strings, invocable via the CLI with the -f flag.[37]
Among popular plugins, eslint-plugin-react provides rules for React and JSX, such as enforcing prop types and key usage in lists, installed via npm install eslint-plugin-react --save-dev.[38] The eslint-plugin-import package focuses on module linting, validating import paths, order, and export consistency to prevent resolution errors.[39] For style integration, eslint-plugin-prettier runs Prettier as an ESLint rule to ensure code formatting aligns with linting, avoiding conflicts between style rules and auto-formatting.[40] These plugins, along with others like @typescript-eslint/eslint-plugin for TypeScript-specific rules, demonstrate ESLint's ecosystem for scalable, framework-agnostic code quality enforcement.
Recent Advancements
As of November 2025, ESLint has introduced several new features to expand its scope and performance. In February 2025, ESLint added official support for linting CSS files, enabling validation and enforcement of baseline CSS features through tolerant parsing and custom syntax support.[41] Additionally, version 9.34.0, released in August 2025, introduced multithreaded linting, allowing parallel processing of files to improve performance on multi-core systems; this can be configured via the CLI with options like --max-threads 4 to specify the maximum number of threads.[13]
Configuration
Basic Setup
To install ESLint, use npm, the Node Package Manager, as it is the primary distribution method. For a local installation, which is recommended to ensure project-specific versions and avoid conflicts in multi-project environments, execute the command npm install eslint --save-dev in your project's root directory. This adds ESLint as a development dependency to your package.json file. Alternatively, for global installation allowing use across multiple projects without npx, run npm install -g eslint, though this approach may lead to version mismatches and is generally discouraged for team collaborations.[7]
Once installed, initialize a basic configuration using the interactive setup wizard. The recommended command for the default flat config format is npm init @eslint/config@latest, which prompts users to select options such as code style preferences (e.g., JavaScript style guide), environment (e.g., browser or Node.js), and framework usage (e.g., React or TypeScript), generating an appropriate configuration file automatically. The legacy command npx eslint --init can still be used but creates a deprecated .eslintrc format. Since ESLint version 9.0.0, released in April 2024, the default format is the flat configuration in eslint.config.js, which offers improved performance and modularity over the legacy .eslintrc.json format.[7][42]
A basic flat configuration example for a browser environment, extending the recommended ruleset, appears as follows:
javascript
import globals from "globals";
import js from "@eslint/js";
export default [
{ files: ["**/*.js"], languageOptions: { globals: globals.browser } },
js.configs.recommended,
];
import globals from "globals";
import js from "@eslint/js";
export default [
{ files: ["**/*.js"], languageOptions: { globals: globals.browser } },
js.configs.recommended,
];
This specifies the browser globals (e.g., window and document) and applies ESLint's recommended rules, such as prohibiting unused variables or undefined references. For legacy support, an equivalent .eslintrc.json file could be created manually with {"env": {"browser": true}, "extends": ["eslint:recommended"]}, but flat config is now the standard.[7][43]
To run the first linting pass on your project files, use the command npx eslint . --ext .js, which scans all JavaScript files in the current directory and subdirectories. ESLint outputs results in the default "stylish" format, displaying file paths, line numbers, error messages, and severity levels (warnings or errors); for alternative formats like JSON for programmatic use, append --format json. If no configuration file exists, ESLint applies a minimal default set of rules, but a proper config ensures targeted enforcement.[7]
Advanced Configuration Options
ESLint provides several advanced configuration options to handle the complexities of large-scale or specialized JavaScript projects, enabling fine-grained control over linting behavior across diverse file patterns, parsers, and shared presets.[11] These features build on basic setups by supporting modular, scalable configurations that can be dynamically imported and extended, particularly useful in monorepos or polyglot codebases.[11]
The flat config system, introduced experimentally in ESLint version 8.21.0 and made the default in version 9.0.0, represents a modern alternative to the legacy .eslintrc format, utilizing an eslint.config.js file (or variants like .mjs, .cjs) that exports an array of configuration objects for enhanced modularity.[11][44] This array-based approach allows configurations to be imported and composed programmatically, such as via dynamic imports, which facilitates better organization in large projects compared to the hierarchical, JSON/YAML-based structure of .eslintrc files.[11] For instance, a basic flat config might be defined as follows:
javascript
import { defineConfig } from "eslint/config";
export default defineConfig([{ rules: { semi: "error" } }]);
import { defineConfig } from "eslint/config";
export default defineConfig([{ rules: { semi: "error" } }]);
This system's advantages include improved performance through reduced parsing overhead and greater flexibility for TypeScript integration, making it the recommended format for new projects since ESLint v9. In March 2025, flat config was further evolved to support the extends property for simpler inheritance from shareable configs, enhancements to defineConfig for type safety and automatic array flattening, and explicit global ignores for better scoping.[11][45]
Overrides enable project-specific rule applications based on file patterns, allowing developers to tailor linting rules to subsets of files without duplicating global configurations.[11] In the flat config format, overrides are specified using files and ignores properties with glob patterns, such as applying stricter rules only to test files while excluding certain directories.[11] An example override configuration might look like:
javascript
{ files: ["**/*.js"], ignores: ["__tests/**"], rules: { "no-console": "error" } }
{ files: ["**/*.js"], ignores: ["__tests/**"], rules: { "no-console": "error" } }
Complementing overrides, the .eslintignore file (or inline ignores arrays) allows global exclusions of files or directories from linting, preventing unnecessary processing of build artifacts or third-party code.[11] For global ignores in flat config, the object contains only an ignores key, e.g.:
javascript
{ ignores: [".config/", "dist/"] }
{ ignores: [".config/", "dist/"] }
This ensures efficient linting scopes in expansive repositories, with enhanced global ignore support added in March 2025.[11][45]
Shareable configurations promote reusability by allowing teams to extend community-maintained presets or publish their own to npm, streamlining adoption of best practices across projects.[11] For example, integrating the @typescript-eslint recommended preset in a flat config involves importing and extending it (supported via extends since March 2025):
javascript
import tseslint from "typescript-eslint";
export default tseslint.config(
tseslint.configs.recommended,
{ rules: { /* custom rules */ } }
);
import tseslint from "typescript-eslint";
export default tseslint.config(
tseslint.configs.recommended,
{ rules: { /* custom rules */ } }
);
Custom shareable configs are published as npm packages named eslint-config-<name>, enabling others to extend them via the extends property (supported in flat config since March 2025) for consistent rule enforcement in frameworks like React or Vue.[11][45]
Parser and language options further customize ESLint's interpretation of source code, supporting advanced JavaScript features and framework-specific globals.[11] Parsers like @babel/eslint-parser can be specified to handle ESNext syntax in transpiled environments:
javascript
{ languageOptions: { parser: require("@babel/eslint-parser") } }
{ languageOptions: { parser: require("@babel/eslint-parser") } }
Additionally, the languageOptions object defines globals for testing frameworks (e.g., it and describe as readonly) or sets ecmaVersion to "latest" for modern ECMAScript support and sourceType to "module" for ES modules, ensuring accurate parsing without false positives.[11] These options are essential for projects using Babel, TypeScript, or browser-specific variables.[11]
Usage and Integration
Command-Line Interface
ESLint provides a command-line interface (CLI) for executing linting tasks directly from the terminal, allowing developers to analyze JavaScript and related files for potential errors, stylistic inconsistencies, and adherence to coding standards.[12] The basic syntax is npx eslint [options] [file|dir|glob]*, where files, directories, or glob patterns specify the targets for linting; if no patterns are provided, ESLint defaults to linting the current directory (.).[12] For instance, running npx eslint src/ processes all JavaScript files in the src directory recursively.[12]
Key flags enhance basic usage, such as --fix to automatically apply safe fixes for reported issues, which modifies the source files in place, or --quiet to suppress warnings and display only errors.[12] Another useful option is --ext .js,.ts to specify file extensions for processing, ensuring ESLint targets the correct file types in a project.[12] These flags enable quick iterations during development without needing integrated development environment (IDE) support.
Output and reporting options allow customization for different environments, including CI/CD pipelines. The --format flag (or -f) controls the output style, with "stylish" as the default for human-readable terminal display; alternatives like "json" produce machine-readable results for scripting or logging, as in npx eslint --format json src/.[12] Reports can be directed to a file using --output-file (or -o), and exit codes indicate success (0 for no errors), errors (1), or warnings exceeding a threshold set by --max-warnings (default 0, meaning any warning fails the process).[12] Caching with --cache stores results in a file (default .eslintcache) to skip unchanged files on subsequent runs, improving performance in large projects when combined with --cache-location for custom paths.[12]
Advanced flags support finer control and debugging. The --rule option overrides specific rules inline, such as --rule 'quotes: [error, "double"]' to enforce double quotes, while --plugin loads external plugins like --plugin react for framework-specific linting.[12] For ignoring patterns, --ignore-pattern excludes files or directories (e.g., --ignore-pattern "/node_modules/"), and --no-ignore bypasses the default .eslintignore file.[12] Debugging tools include --debug for verbose logging and --env-info to output environment details, aiding troubleshooting.[12] Input can also come from standard input via --stdin, useful for piping code, as in cat myfile.js | npx eslint --stdin --stdin-filename myfile.js.[12]
Integration into build pipelines is facilitated through scripting, commonly via package.json scripts like "lint": "eslint src/" or "lint:fix": "eslint --fix src/", which can be invoked with npm run lint to enforce code quality as part of workflows.[7] The CLI respects a configuration file (e.g., eslint.config.js) specified with -c or defaults to one in the project root.[12]
Editor and IDE Integrations
ESLint integrates seamlessly with popular editors and integrated development environments (IDEs), providing real-time feedback on code issues directly within the development workflow.[46] This allows developers to catch and resolve linting errors as they write code, enhancing productivity without relying solely on command-line executions.[47]
In Visual Studio Code, the official ESLint extension developed by Microsoft enables comprehensive integration by leveraging the ESLint library installed in the workspace folder or globally.[47] It highlights errors and warnings inline with single-line underlines, supports code actions for quick fixes, and allows automatic fixing of issues on save through the editor.codeActionsOnSave setting configured with source.fixAll.eslint.[47] Configuration synchronizes with workspace settings via options like eslint.workingDirectories for multi-root setups and eslint.validate to specify file types such as JavaScript and TypeScript.[47] The extension adapts to ESLint versions, using the CLIEngine API for versions below 8 and the ESLint class for version 8 and above, ensuring compatibility with flat configuration files like eslint.config.js since ESLint 9.[47]
WebStorm and IntelliJ IDEA offer built-in support for ESLint, allowing real-time linting that displays warnings and errors directly in the editor as code is typed.[48] This integration supports a wide range of rules extensible via plugins and works with file types including JavaScript and TypeScript, with configurable linting scopes limited to specific project directories or files.[48] It also accommodates styles like JavaScript Standard Style and provides options to run ESLint on save or during editing for immediate feedback.[48]
For terminal-based editors, Vim and Neovim integrate ESLint through the Asynchronous Lint Engine (ALE) plugin, which performs asynchronous linting to check syntax and semantics without blocking the editor.[49] ALE runs ESLint in real-time as text changes, configurable via g:ale_linters = {'javascript': ['eslint']} in the vimrc or filetype-specific plugins, and supports auto-fixing with the :ALEFix command using ESLint as the fixer.[49] Similarly, Emacs uses the Flycheck package with the javascript-eslint syntax checker to integrate ESLint, automatically selecting it for JavaScript modes like js-mode and providing real-time error highlighting based on flycheck-check-syntax-automatically.[50] Configuration in Emacs can specify local ESLint executables via flycheck-set-checker-executable to use project-specific installations from node_modules.[50]
Browser-based integrations for ESLint are limited, primarily supporting development through browser extension dev tools for quick checks rather than full real-time linting in desktop IDEs.[46]
Best practices for these integrations include enabling auto-fix on save—such as setting eslint.codeActionsOnSave.mode to "all" in VS Code or g:ale_fix_on_save = 1 in ALE—to automatically resolve fixable issues during editing.[47][49] To avoid unnecessary processing, ignore directories like node_modules using global ignore patterns in eslint.config.js with globalIgnores(["**/node_modules/"]) or via a .eslintignore file, ensuring consistent behavior across editors and the command-line interface.[51] For troubleshooting common issues like parser mismatches, verify compatibility between ESLint and the specified parser (e.g., @typescript-eslint/parser for TypeScript) in the configuration's languageOptions.parser setting, and enable debug modes like eslint.debug in VS Code to log errors.[8][47]
Adoption and Community
Usage Statistics
ESLint stands as the premier JavaScript linter, with over 65 million weekly downloads on npm as of November 2025, solidifying its position as the number one tool in its category.[1]
The tool enjoys widespread industry adoption, with major organizations such as Microsoft, Airbnb, Netflix, and Meta incorporating ESLint into their workflows to enforce code quality standards.[1]
Adoption rates for ESLint continue to grow, fueled by its seamless compatibility with ecosystems like TypeScript and React, which have expanded the demand for robust linting solutions.[1] Teams implementing ESLint have reported improvements in code reliability through early detection of potential issues.[52]
In comparison to competitors, ESLint far surpasses legacy tools like JSHint, whose usage has steadily declined due to limited extensibility, while newer entrants such as Biome remain niche with under 10% market penetration despite performance advantages in specific benchmarks.
Contributions and Governance
ESLint is maintained by a dedicated team under the governance of the OpenJS Foundation, which owns the project's intellectual property and provides legal infrastructure while leaving daily operations to the ESLint team.[53] The Technical Steering Committee (TSC), limited to a maximum of five members, oversees the project's technical direction, release processes, and team membership.[54] Decisions are made through biweekly TSC meetings held on Discord, where consensus is sought, falling back to majority vote if necessary; GitHub issues tagged with "tsc agenda" are prioritized for discussion.[54]
Contributions to ESLint follow a standard open-source workflow, beginning with forking the GitHub repository, creating a feature branch with descriptive naming, implementing changes in line with code conventions and Conventional Commits standards, running tests via npm test, and submitting a pull request for review.[55] Contributors can focus on areas such as core rules (for bug fixes or enhancements), documentation updates, or plugin development, with pull requests reviewed by TSC members or designated committers.[55] The project enforces the OpenJS Foundation Code of Conduct, which promotes an inclusive environment welcoming participation from all individuals regardless of background.[56] All contributors must sign a Contributor License Agreement to ensure compatibility with the project's Apache 2.0 license.[55]
Community engagement is facilitated through multiple channels, including the ESLint Discord server for real-time discussions, the @geteslint Twitter account for announcements, and the official blog for in-depth updates on releases and features.[57][58][59] As of November 2025, ESLint is supported by 150 sponsors—companies, organizations, and individuals—contributing $11,147 monthly, or approximately $133,764 annually, primarily through Open Collective and GitHub Sponsors; these funds support team compensation, project development, and ecosystem initiatives.[60]
Sustaining the project involves addressing challenges such as rule and configuration deprecations to evolve with modern JavaScript practices, exemplified by the planned removal of the legacy eslintrc system in ESLint v10.0.0 (expected late 2025), which will require users to migrate to the flat config format for continued compatibility.[24] Deprecated rules receive no further maintenance, including bug fixes or documentation updates, to minimize disruption while encouraging adoption of equivalents in core or plugins.[61] To enhance scalability, the team actively welcomes new maintainers by inviting experienced contributors to join after demonstrating consistent involvement, such as through multiple qualifying pull requests, with connections facilitated via Discord.[53][54] The most recent release, v9.39.1 on November 3, 2025, includes bug fixes and minor enhancements, underscoring active maintenance.[62]