-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Description
Suggestion
tl;dr: We get asked pretty frequently about improving the state of cross-file linting, e.g. typed linting, in ESLint core. Most requests are around performance. Others are around core ESLint features such as caching and multi-threaded linting. We'd love to optimize those use cases, but:
- ESLint itself does not include what we'd need to to do so
- Our suggestions were not accepted in the ESLint RFC process.
We hope that ESLint will evolve long-term to support cross-file, stateful linting as needed for typed linting. In the meantime, this meta-issue tracks the assorted typescript-eslint improvements blocked on ESLint core. The past biggest ones have been:
- Purge programs once they are done #1718
- Cleanup old file/folder watch callbacks #3536
- --fix flag doesn't work with custom Program #3834
- Docs: type-aware linting is not safe to use with
eslint --cache#4694 - Interaction with multithread linting #11568
Full context: ESLint today does not have any native concepts of cross-file dependencies, stateful parsing, or type information. It intentionally adopts a "trivial" parallelization strategy that works very well for highly parallelizable parsers and rules. However, the typescript-eslint parser -which is what also provides type information- and other cross-file lint mechanisms (such as some eslint-plugin-import rules) are not well suited to that kind of simplistic parallelization.
We've made several suggestions to ESLint over the years for adding in some kind of native allowance that would let typed linting optimize. Most recently we provided this feedback for the concurrent linting RFC. But the ESLint TSC has either rejected or deferred our suggestions, citing a desire to address the concerns later as part of their impending redesign of the parts of ESLint's internals. Unfortunately that's left us in this in-between state where some core ESLint features -most notably: caching and now concurrency- are broken or sub-par for typed linting and other cross-file linting systems.
In terms of typed linting with caching, concurrency, and performance optimizations, the root issue is that ESLint treats a parser as a stateless function. This means that each parser instance is not told anything about what ESLint is doing; for example it does not know that it's in concurrent mode. That makes it difficult or impossible to limit expensive work such as setting up full module dependency graphs (eslint-plugin-import & co.) or producing type information for all files (typed linting). Parsers don't even know right now what form of session (CLI, CLI with --fix, editor) ESLint is being run as!
In theory a parser could work around those limitations. For example, it could use one of a few techniques to do blocking, synchronous communication with a shared thread. However we would ultimately just be hacking around limitations of ESLint's design. We have implemented some hacks where possible, such as inferring single-run mode (disallowAutomaticSingleRunInference). But doing so is quite fragile even for simple cases and when it breaks it causes frustrating and confusing bugs for users. We just don't have the maintenance budget to develop elaborate, likely brittle shims around what should ideally be provided upstream.
ESLint's caching and new concurrency features are obviously a huge win for many codebases: definitely for those not using typed linting, and for concurrency, even for some that are. And we of course would be thrilled to support both natively in typescript-eslint. But until the ESLint rewrite process gets to the point of working on project-aware and/or cross-file-aware architectures, there is nothing that we can reasonably do.
Here's a quick summary of past discussions:
- eslint/eslint#13525 Add parser lifecycle hooks (mid 2020): Brad had suggested adding lifecycle hooks -- auto-closed without activity
- eslint/rfcs#42 feat: Lint files in parallel if many files exist (late 2019 through 2021): Brad noted large codebases are more likely to OOM due to shared memory. btmills posted a good summary of the choices to make.
- eslint/eslint#14139 (early 2021): btmills filed a proposal for an API to allow plugins to up-front initialisation/setup work. Brad provided extensive notes about how type-aware linting worked and what we would like to be implemented. Closed in 2025 due to age without much discussion.
- eslint/rfcs#87 feat!: Support async parsing (early 2022): closed with the intent of addressing in larger rewrite.
- eslint/rfcs#102 feat: parsing session objects (late 2022 through early 2023): We requested info that we'd need to optimize. Similarly closed with the intent of addressing in a larger rewrite.
- eslint/rfcs#112 feat: Initial RFC for sharding (mid 2023): Brad explained why type-aware linting (and import plugin work) is expensive to do multiple times. OP dropped out.
- eslint/rfcs#129 feat: multithread linting (late 2024 through mid 2025): merged without explicit handling of cross-file cases
Additional Info
We've closed the other issues so they don't take up as much space in our issue tracker. It's going to be a long while until ESLint core supports the use cases we need. Until then, we'll try to keep this issue updated & link new requests as they come in or get re-found.
This post was co-authored by @bradzacher and @kirkwaiblinger, and originally posted as #11568 (comment).
💖