Monorepo Configuration
The new "project service" in v8 requires no additional configuration for monorepos.
If you're using parserOptions.projectService
, you don't need this guide.
If you're using a monorepo with parserOptions.project
, these docs will help you figure out how to setup typed linting.
If you don't want to use typed linting, then you can stop here - you don't need to do anything special.
parserOptions.project
configurations will look different based on which monorepo setup you use:
One root tsconfig.json
If you only have one tsconfig.json
file and its include
paths include all the files you'd like to lint, you can directly use it with typescript-eslint without further configuration.
If its include
paths cannot include all files to be linted, we suggest creating a new config called tsconfig.eslint.json
, that looks something like this:
{
// extend your base config to share compilerOptions, etc
"extends": "./tsconfig.json",
"compilerOptions": {
// ensure that nobody can accidentally use this config for a build
"noEmit": true,
},
"include": [
// whatever paths you intend to lint
"src",
"test",
"tools",
],
}
Be sure to update your ESLint configuration file to point at this new TSConfig.
One tsconfig.json
per package (and an optional one in the root)
The parserOptions.project
option introduced in Linting with Type Information accepts an array of relative paths.
Paths may be provided as Node globs.
For each file being linted, the first matching project path will be used as its backing TSConfig.
- Flat Config
- Legacy Config
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
project: true,
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
tsconfigRootDir: import.meta.dirname,
},
},
},
);
/* eslint-env node */
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended-type-checked',
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: true,
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
tsconfigRootDir: import.meta.dirname,
},
plugins: ['@typescript-eslint'],
root: true,
};
Wide globs in parserOptions.project
Using wide globs **
in your parserOptions.project
may degrade linting performance.
Instead of globs that use **
to recursively check all folders, prefer paths that use a single *
at a time.
- Flat Config
- Legacy Config
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
project: ['./tsconfig.eslint.json', './**/tsconfig.json'],
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
tsconfigRootDir: import.meta.dirname,
},
},
},
);
/* eslint-env node */
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-type-checked',
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: ['./tsconfig.eslint.json', './**/tsconfig.json'],
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint'],
root: true,
};
See Glob pattern in parser's option "project" slows down linting for more details.
Important note regarding large (> 10) multi-package monorepos
We've had reports that for sufficiently large and/or interdependent projects, you may run into OOMs using this approach. Our advice is to set it up and test first, as there are very few cases that trigger this OOM.
See #1192 for more information and discussion.
If you do run into an OOM, please comment on the above issue and let us know about your repo - the more information we have, the better. As an interim workaround, consider one of the following:
- Switching to one root
tsconfig.eslint.json
(see One roottsconfig.json
) - Using a shell script to only lint one package at a time, using your existing config above.