Linting at Scale:
Strategies for Updating ESLint Configs in Large Applications

Published on: August 15, 2025

In this article, we will explore strategies for updating ESLint configurations in large applications. As applications grow, maintaining a consistent and effective linting strategy becomes crucial for code quality and team productivity.

📚 TL;DR? I've created a complete, copy-paste ESLint configuration that you can grab from my dev resources repository. It includes all the configs, installation commands, and setup instructions. Feel free to implement it first, then circle back to understand the "why" behind each decision!

Reviewing Your Current ESLint Setup

You might be dealing with a large codebase where certain areas have broken linting, or where rules vary from one part of the application to another.

In any case, your first step should be to review your existing ESLint configuration to spot gaps and inconsistencies.

Move to ESLint’s Flat Config Format (If You’re Not Using It Yet)

ESLint Flat Config introduces a more refined and modular way to set up your project’s linting rules. With flat config, your ESLint settings become easier to organize, update, and maintain—making it well-suited to large codebases and evolving projects.

If you’re ready to transition, the official migration guide walks you through the process of converting your existing configuration to the new flat config format, step by step.

Update Your ESLint Config to Match Your Project Needs

After reviewing your current ESLint configuration, the next step is to establish a fresh set of coding standards. This might involve refining existing rules, introducing new ones, or removing those that no longer serve a purpose. The aim is to build a clear, consistent, and effective linting strategy tailored to your project’s needs.

Pick and Stick to a Code Formatting Standard

Everyone’s got their own take on coding style, but it’s worth agreeing on something the whole team can stick to.

Run a quick poll to see what your team prefers. Go with the majority— it’s about what works best for the team, not just your personal pick.

Update your .prettierrc file to reflect this choice, and make sure your ESLint configuration aligns with it. Popular plugins like eslint-config-prettier can help automatically disable conflicting rules.

Take Advantage of Predefined ESLint Configurations

Instead of figuring out every rule from scratch, you can use predefined ESLint configurations that match your team's coding standards. These popular community-maintained configs save time and effort. Some common examples include eslint:recommended and eslint-plugin-unicorn.

Define a Global Configuration File

Once you have your coding standards in place, the next step is to define a global ESLint configuration file. This file will serve as the foundation for your linting rules across the entire application. It should include the core rules that apply universally, such as indentation style, line length, and other fundamental coding standards.

javascript
1// eslint/common.config.ts
2import tseslint, { configs as tseslintConfigs } from 'typescript-eslint';
3
4import {
5	defaultExtends,
6	defaultPlugins,
7	defaultRules,
8	defaultSettings,
9	languageOptions,
10	testFiles,
11} from './utilities';
12
13export default tseslint.config(
14	{
15		ignores: [
16			'package-lock.json',
17			'yarn.lock',
18			'node_modules/**',
19			'.firebase/**',
20			'.next/**',
21			'out/**',
22			'next-env.d.ts'
23		],
24	},
25	{
26		files: ['**/*.ts', '**/*.js'],
27		ignores: testFiles,
28		plugins: defaultPlugins,
29		extends: defaultExtends,
30		rules: defaultRules,
31		settings: defaultSettings,
32		languageOptions,
33	},
34	{
35		files: ['eslint.config.ts', 'eslint/**/*.ts'],
36		extends: [tseslintConfigs.disableTypeChecked],
37	}
38);

Define Project Specific Configuration Files

For large applications, it’s common to have multiple projects or modules that may require specific linting rules. In such cases, you can create project-specific ESLint configuration files. These files extend the global configuration and include additional rules that are relevant only to that particular project.

javascript
1// .eslint.config.ts
2import common from './eslint/common.config';
3import react from './eslint/react.config';
4import tests from './eslint/tests.config';
5
6export default [...common, ...tests, ...react];

For example, you may want lenient rules for your tests, while ensuring stricter rules for your production code. This allows you to maintain a balance between code quality and development speed.

javascript
1// eslint/tests.config.ts
2import tseslint, { configs as tseslintConfigs } from 'typescript-eslint';
3
4import {
5	defaultSettings,
6	languageOptions,
7	testFiles,
8	tsRules,
9} from './utilities';
10
11export default tseslint.config({
12	files: testFiles,
13	plugins: {},
14	// reduced set of rules for tests
15	extends: [...tseslintConfigs.recommended],
16	rules: tsRules,
17	settings: defaultSettings,
18	languageOptions,
19});

Set up Pre-Commit Hooks to Start Enforcing New Linting Rules on Problematic Files Overtime

After setting up your ESLint configurations, you might encounter many errors across your codebase. This is where pre-commit hooks become invaluable. They help enforce the new linting rules gradually by checking only the files being changed, allowing you to fix issues over time instead of tackling everything all at once.

Find Problematic Files in Your Codebase

To identify which files are causing issues, auto-format your codebase using Prettier first and then run ESLint to pick up any remaining files with problems.

bash
1prettier --write .
2eslint . --config path/to/eslint.config.js --quiet --format json \
3	| jq -r '.[] | select(.errorCount > 0) | .filePath'

I would recommend running the auto-format command on your repository and committing the changes before enforcing the new formatting rules. This would ensure that your team doesn't have to deal with a lot of merge conflicts when you start enforcing the new linting rules.

Ignore These Files for Linting Until They Are Worked Upon

Once you have identified the files with issues, you can set up ESLint to ignore these files when running the linter. This allows you to focus on fixing issues in files that are actively being worked on, while ignoring those that are not currently being modified.

json
1// eslint/ignored_files.json
2{
3	"files": [
4		// these files are ignored by eslint
5		"src/path/to/file.ts",
6		"src/path/to/file2.ts"
7	]
8}
javascript
1// eslint/legacy.config.ts
2import tseslint from 'typescript-eslint';
3
4import { files as ignores } from './ignored_files.json';
5
6export default tseslint.config({
7    ignores,
8});
javascript
1// eslint.config.ts
2import legacy from './eslint/legacy.config';
3import common from './eslint/common.config';
4import react from './eslint/react.config';
5import tests from './eslint/tests.config';
6
7export default [...legacy, ...common, ...tests, ...react];

Setup Pre-commit Hooks to Enforce New Linting Rules on Files Being Changed

Your pre-commit hook should first check whether the file being committed is excluded from linting. If it is, the hook needs to remove that exclusion from eslint/ignored_files.json and then run ESLint on the file before allowing the commit to proceed. The updated eslint/ignored_files.json file should also be included in the same commit.

The actual shell script that does this is too large to be included in this blog post. You can find it in my companion code repository: here.

If you changed a file that was previously ignored, the pre-commit hook log should look like this:

bash
1$ git commit -m "feat: add new feature"
2
3Running prettier --write on staged files...
4- Auto-formatted 3 files.
5
6Running ESLint legacy checks...
7- You are trying to commit changes to files that are ignored by ESLint.
8- Updated eslint/ignored_files.json to remove such files.
9- Added eslint/ignored_files.json to staging area.
10
11Running ESLint checks...
12- No linting errors found.

Back it up with Solid CI/CD Pipeline

Finally, ensure that your CI/CD pipeline is set up to run ESLint checks on every PR. This will help catch --no-verify bypasses, accidental file exclusions, and ensure that all code changes adhere to the new linting rules.

You can see a working example of a CI/CD pipeline that runs ESLint checks by visiting my companion code repository: here

Conclusion

Updating ESLint configurations in large applications can be a daunting task, but with the right strategies, it becomes manageable. By reviewing your current setup, defining clear coding standards, and implementing pre-commit hooks, you can ensure that your codebase remains clean, consistent, and maintainable over time.

Remember, the goal is to create a linting strategy that works for your team and project. Don’t hesitate to iterate on your configuration as your project evolves.

In this article