Fine‑Tune Linting in a Monorepo with ESLint Overrides
In a large monorepo, a single ESLint config can’t satisfy every package. ESLint’s "overrides" let you tailor rules per package or language, keeping a single config file while avoiding false positives. This guide shows how, with a concrete example, the trade‑offs, and best‑practice actions.
08 Mar 2026, 05:53 UTC

Problem: One‑Size‑Fits‑All Linting Breaks a Monorepo
When a monorepo contains multiple libraries or applications that target different runtimes (Node, React, TypeScript, etc.), a single .eslintrc.json often forces a compromise. A rule that is useful for one package may be an annoyance in another, leading to noisy lint output or the temptation to disable the rule globally.
Thesis: Use ESLint overrides to Keep a Single Config, Not a Collection of Files
ESLint’s overrides array lets you apply rule sets to specific file patterns. The base config contains the common rules, while each override targets a package or language and adds or modifies rules. This keeps configuration DRY, centralizes rule ownership, and eliminates the need for multiple .eslintrc.* files scattered across the repo.
How Overrides Work
files– Glob pattern(s) that match the files the override applies to.rules– Object of rule names to configuration values. These merge with the base config; keys in the override override the base values.plugins,extends, etc. – You can also add plugins or extend other configs locally.
Overrides are processed in order. The first matching override is applied, then subsequent overrides that match the same file merge in. This allows cascading rule changes if needed.
Worked Example: Two Packages, One Rule Exception
Suppose a monorepo has two packages:
packages/core– pure Node library.packages/ui– React component library.
We want no-console to be a warning in core (allow console for debugging) but an error in ui (disallow console in UI code). A single base config would force us to pick one severity.
Configure .eslintrc.json at the repo root:
{
"env": {
"node": true,
"browser": true
},
"extends": [
"eslint:recommended"
],
"rules": {
"no-console": ["error", {"allow": ["warn", "error"]}]
},
"overrides": [
{
"files": ["packages/core/**/*.js"],
"rules": {
"no-console": ["warn"]
}
},
{
"files": ["packages/ui/**/*.js"],
"rules": {
"no-console": ["error"]
}
}
]
}
Run linting from the repo root:
# Requires write access to the repo.
# ESLint reads the configuration from .eslintrc.json.
eslint .
Verification steps:
- Place a
console.log('debug');inpackages/core/index.jsand runeslint .. You should see a warning only for that file. - Place a
console.log('debug');inpackages/ui/Button.jsand runeslint .. You should see an error only for that file. - Inspect the resolved config for each file:
eslint . --print-config packages/core/index.jsandeslint . --print-config packages/ui/Button.js. Verify that theno-consolerule shows the correct severity.
Trade‑Offs and Limitations
- Complexity: Too many overrides can make the configuration hard to read. Keep the number of blocks manageable and document the intent of each.
- Plugin Scope: If a plugin is required only for a subset of files, list it in the override’s
pluginsfield. Loading a plugin globally may cause it to run on files it shouldn’t, generating false positives. - Performance: ESLint processes overrides for every file. In very large repos, a highly granular override set may add overhead. Benchmarks show negligible impact for typical monorepo sizes.
- Migration: Moving an existing
.eslintrc.*from a package into an override can be error‑prone if the package’s config usedextendschains that reference external configs. Verify by runningeslint --print-configafter migration.
Actionable Take‑Away
1. Keep a single .eslintrc.json at the repo root.
2. Add an overrides array that targets each package’s glob.
3. For each override, add only the rules that differ from the base config; let the base cover common rules.
4. Verify with eslint --print-config and run linting on a subset of files to ensure overrides behave as expected.
5. Document each override in a README or comment block to aid future maintainers.
Using overrides gives you the flexibility of per‑package linting without fragmenting your configuration. It centralizes rule ownership, reduces duplication, and keeps your monorepo clean.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.