# typescript-eslint: the monorepo behind TypeScript linting

> Most TypeScript projects never read this repository, they just install its packages. Here is what the monorepo actually contains, how the type-aware rules get their information, and where the README stops.

**typescript-eslint/typescript-eslint** — :sparkles: Monorepo for all the tooling which enables ESLint to support TypeScript

- Repository: https://github.com/typescript-eslint/typescript-eslint
- Website: https://typescript-eslint.io
- Stars: 16,412 · Forks: 3,025
- Language: TypeScript
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/typescript-eslint-typescript-eslint

## One repository, several published packages

The starting point is that typescript-eslint is a monorepo, not a plugin. The root `package.json` is marked `"private": true` and declares workspaces covering `packages/*`, so the root project is never published. What npm consumers install are the individual packages built out of that workspace, which is why the repository's own name, `@typescript-eslint/typescript-eslint`, never appears in your lockfile.

The scripts in that root file describe the shape of the build better than any prose would. Build runs through Nx and explicitly excludes two projects by name:

```json
"build": "nx run-many -t build --exclude website website-eslint"
```

Clean runs in parallel with a cap of twenty, and there are separate Nx targets for lint, a stylelint pass over the website, and a website-specific build for generating type declarations used by the docs site. Two projects, `eslint-plugin` and `eslint-plugin-internal`, are treated specially throughout, and the release notes name a third package, `utils`, when something changes there. That naming convention, package name in brackets before the change, is a small but useful signal when you are reading a release and wondering which install would be affected.

The tree is mostly configuration at the top level: `eslint.config.mjs`, four separate `tsconfig` files for base, build, spec and repo config files, `nx.json`, `knip.ts`, `pnpm-workspace.yaml`, plus `tools/` and `docs/`. That is a repository where the interesting code is one directory down.

## What the parser adds that plain ESLint does not have

The repository description is a monorepo for all the tooling which enables ESLint to support TypeScript, which is a compressed way of saying the work happens at three layers: parse, scope, and rule.

The parser package converts TypeScript syntax into an AST that ESLint's traversal machinery can walk, which is a prerequisite rather than the interesting part. TypeScript's grammar has constructs plain JavaScript does not have, so a parser that did not understand them would leave ESLint's scope analysis blind in exactly the places where bugs live.

The second layer is type information, and this is where the design decision that shapes everything else appears. A rule like `no-floating-promises` cannot be written without knowing that a call returns a `Promise`. Getting that knowledge requires a TypeScript program, which means reading `tsconfig.json`, loading the compiler, and paying for it on every lint run. The release notes give a glimpse of the machinery underneath: a v8.70.0 fix for `project-service` to avoid discarded tsserver logs is not a lint rule change at all, it is an edit to the process that keeps the type information warm between runs.

So there are two workable modes. Without type information you get syntax-level rules that run fast. With it you get the rules that catch real defects, at a cost in memory and startup time. The README does not discuss this tradeoff at all, which is why it is worth understanding before you enable a large rule set on a large codebase.

## Reading the release notes as an engineering diary

The three most recent releases in this repository are v8.70.0 on 2026-09-07, v8.69.0 on 2026-08-31 and v8.68.0 on 2026-08-24. That is one release a week, and the contents are unusually revealing about where the difficulty lives.

New rules arrive slowly, roughly one per release. v8.70.0 added `no-generated-empty-object-type`, v8.69.0 added a `flagUnions` option to `no-misused-promises`, v8.68.0 added fix suggestions to `strict-void-return`. Compare that with the fix lists, which run five to eight items each. A typical week includes `no-unnecessary-condition` producing a false positive on the right-hand side of a nested logical expression, `member-ordering` reporting fields that read fields declared before them, and `no-deprecated` missing deprecated imported values used in object shorthand properties.

Those three are all the same class of bug: the rule fires on code that is correct. Type-aware linting lives at the boundary where a value's runtime shape and its declared type disagree, and that boundary is where false positives breed. Two fixes from v8.68.0 point the other way, at rules that were too quiet: `no-floating-promises` producing a false negative on an arrow function when `ignoreVoid` was false, and `no-unnecessary-type-assertion` overflowing the stack on recursive types.

A stack overflow on a recursive generic type is a good illustration of the underlying problem. Any rule that walks a type has to decide when to stop, and TypeScript's types can nest through aliases in ways that have no natural depth limit. The fix is a depth or cycle guard, which is the sort of change that only appears after someone runs the linter on code shaped like a recursive data structure.

## The split between what a rule set covers and what it does not

Anyone arriving from TSLint asks whether the tool still exists and whether it is worth switching. The migration happened years ago and the direction of travel is settled: ESLint plus these packages is the supported path for TypeScript, and the repository topics still list `tslint` alongside `eslint`, `eslint-plugin` and `typescript`, which reads as a migration history rather than an ongoing commitment to both.

Prettier is the other comparison that comes up constantly, and it is a category error worth naming precisely. Prettier formats code and makes no claims about whether code is correct. ESLint and this plugin make claims about correctness. The overlap is a small number of stylistic rules, and typescript-eslint ships a recommended config that deliberately leaves formatting to a formatter so the two tools stop fighting. If your CI currently fails on formatting, that problem belongs to Prettier, and turning on more lint rules will not fix it.

The practical consequence is that rule selection is a design decision per project rather than a default to accept. There are type-checked rule sets that only work with a program, recommended sets that are conservative, and strict sets that will generate a long list on an existing codebase. The `lint-prune-suppressions` script in the root package.json hints at the migration path the project itself endorses:

```json
"lint-prune-suppressions": "nx run-many -t lint --projects=eslint-plugin-internal,eslint-plugin --prune-suppressions"
```

The `--prune-suppressions` flag and the `eslint-suppressions.json` file at the repository root point to a strategy of recording existing violations rather than fixing them all at once, then removing those records as code is touched. That is a better answer than a blanket disable comment, and it explains why the file is committed rather than ignored.

## Where the README stops and the website begins

This README is unusually short, and the reason is stated plainly near the top: typescript-eslint.io holds documentation for the latest released version, and a separate Netlify preview holds docs for the canary release on `main`. Everything technical lives on those two sites. The rest of the README is badges, an OpenCollective contributor section, and an MIT license line.

That split has a practical consequence for anyone evaluating the project. You cannot learn how to configure a rule set from this repository, because the repository does not try to be that document. You can learn a great deal about how the project is built and how it is maintained: the workspace layout, the Nx targets, the tooling for spell checking and formatting, the fact that `docs/` and `website` are separate concerns from the published packages.

The numbers put the maintenance question in perspective. The repository has roughly 16,400 stars, about 3,000 forks, an MIT license, and 232 open issues, and the last push recorded on the default branch is 2026-09-21, ten days before the release of v8.70.0. A weekly release cadence with named maintainers in the package metadata, ongoing sponsor funding through OpenCollective, and Netlify hosting for the docs are all signs of a project with people attached to it rather than one running on inertia.

What you get by reading the releases is a clear picture of priorities: correctness of existing rules, careful handling of TypeScript's type system at its edges, and steady work on the documentation site. What you will not find is a migration guide or a configuration reference, because those are deliberately hosted elsewhere.

## Conclusion

typescript-eslint earns its position by being the layer that lets an existing ESLint setup understand a typed language, and the repository shows the cost of doing that honestly. The parser, the plugin, the scope manager and the type-aware rules all live in one pnpm and Nx workspace, and the weekly v8 releases are dominated by fixing false positives rather than adding new capability. The practical entry points are the `@typescript-eslint/parser` and `@typescript-eslint/eslint-plugin` packages and the generated flat configs, not the monorepo itself. The README is deliberately thin here: it points at typescript-eslint.io for the released docs and at a Netlify preview for canary docs, and everything about rule configuration lives on those two sites rather than in the repository.

## FAQ

### Is TSLint deprecated?

The direction of travel has been settled for years: ESLint plus the typescript-eslint packages is the supported path for linting TypeScript, and this repository's own metadata still lists `tslint` as a topic alongside `eslint` and `eslint-plugin`, which reads as a record of that migration rather than an ongoing commitment to both tools. New rules, fixes and releases land in the ESLint plugin, not in a TSLint successor.

### What is the best linter for TypeScript code?

For most projects the answer is ESLint configured with the `@typescript-eslint/parser` and `@typescript-eslint/eslint-plugin` packages, formatted separately by Prettier. The deciding factor is whether you want type-aware rules: those that flag floating promises, unnecessary conditions and misused promises need a TypeScript program, which costs memory and startup time but catches defects that syntax alone cannot see.

### What is prettier vs ESLint?

They do different jobs and the overlap is small. Prettier reformats code to a consistent style and makes no claims about whether the code is correct. ESLint with these packages reports problems, including type-aware ones. The recommended configurations leave formatting alone on purpose so the two tools do not fight over the same lines.

## Sources

- [License: MIT](https://github.com/typescript-eslint/typescript-eslint/blob/main/LICENSE)
- [Project website](https://typescript-eslint.io)
- [README](https://github.com/typescript-eslint/typescript-eslint/blob/main/README.md)
- [Releases](https://github.com/typescript-eslint/typescript-eslint/releases)
- [typescript-eslint/typescript-eslint on GitHub](https://github.com/typescript-eslint/typescript-eslint)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/typescript-eslint-typescript-eslint
