Question
How to Fix "parserOptions.project" Errors in ESLint with TypeScript
Question
I created a new React Native project using the TypeScript template. After that, I deleted the template directory that came with the boilerplate and added ESLint with this configuration:
module.exports = {
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
extends: ["airbnb-typescript-prettier"]
};
However, when I open babel.config.js, I get this error:
Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: /Users/Dan/site/babel.config.js.
The file must be included in at least one of the projects provided.
Why does this happen, and how can I configure ESLint correctly so that JavaScript config files like babel.config.js do not cause this error?
Short Answer
By the end of this page, you will understand why ESLint sometimes throws a parserOptions.project error in TypeScript projects, especially for files like babel.config.js that are not part of tsconfig.json. You will learn what typed linting is, why ESLint checks TypeScript project boundaries, and the common ways to fix the problem in real projects.
Concept
When ESLint uses @typescript-eslint/parser with type-aware linting, it does more than read syntax. It also loads your TypeScript project configuration from tsconfig.json so it can understand types.
That is what parserOptions.project is about.
If ESLint is told to use a TypeScript project, then every file being linted must belong to that project. A file such as babel.config.js is usually a plain JavaScript config file, and it is often not included in tsconfig.json. When ESLint tries to lint it using the TypeScript parser in project mode, it fails because TypeScript does not consider that file part of the project.
This usually happens indirectly. In your config, airbnb-typescript-prettier commonly brings in settings that expect TypeScript project information. So even if you did not explicitly write parserOptions.project, the extended config may effectively require it.
Why this matters:
- Type-aware linting enables more powerful rules.
- But it also requires correct project boundaries.
- Mixed codebases often contain:
- TypeScript source files
- JavaScript config files
- build scripts
- test setup files
- These files should not always be linted the same way.
The fix is usually one of these:
- Ignore config files that should not be linted with the TypeScript project.
- Use ESLint overrides so
.jsconfig files use the default parser or a non-type-aware setup.
Mental Model
Think of tsconfig.json as a guest list for a private event.
- TypeScript files included in
tsconfig.jsonare on the list. - ESLint with
parserOptions.projectasks TypeScript to verify each guest. babel.config.jsarrives at the door.- TypeScript checks the guest list and says: "This file is not invited."
- ESLint then shows the parsing error.
So the problem is not that babel.config.js is invalid JavaScript. The problem is that ESLint is asking TypeScript to treat it like a file from the TypeScript project, but it is not on the project's list.
Syntax and Examples
A common TypeScript ESLint setup looks like this:
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json"
},
plugins: ["@typescript-eslint"],
extends: [
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking"
]
};
This enables rules that require TypeScript type information.
If ESLint also tries to lint babel.config.js, you may get an error because that file is not included in tsconfig.json.
Option 1: Ignore config files
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json"
},
plugins: ["@typescript-eslint"],
extends: ["airbnb-typescript-prettier"],
ignorePatterns: ["babel.config.js", "metro.config.js"]
};
Use this when you do not need ESLint to check those files.
Step by Step Execution
Consider this ESLint config:
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json"
}
};
And assume tsconfig.json includes only TypeScript source files:
{
"include": ["src/**/*", "App.tsx"]
}
Now ESLint opens babel.config.js.
What happens step by step
- ESLint starts linting
babel.config.js. - It sees that the parser is
@typescript-eslint/parser. - Because
parserOptions.projectis set, the parser loadstsconfig.json. - TypeScript checks whether
babel.config.jsis part of the project. - It is not listed in
include, and it is not a TypeScript source file in the project.
Real World Use Cases
This issue appears often in projects that mix TypeScript application code with JavaScript tooling files.
Common examples:
- React Native apps with
babel.config.jsandmetro.config.js - React apps with
vite.config.jsorwebpack.config.js - Node.js projects with
jest.config.jsoreslint.config.js - Monorepos with multiple
tsconfig.jsonfiles - Build scripts stored in
scripts/*.js
Typical situations:
- You want strict TypeScript linting for
src/**/*.tsandsrc/**/*.tsx. - You still want ESLint on config files.
- But those config files should not require TypeScript project type information.
This separation is very normal in production codebases. Most real projects do not treat all files the same.
Real Codebase Usage
In real projects, developers usually handle this with one of a few patterns.
Pattern 1: Type-aware linting only for TypeScript files
This is the most common setup.
module.exports = {
root: true,
overrides: [
{
files: ["*.ts", "*.tsx"],
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json"
},
extends: [
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking"
]
},
{
files: ["*.js"],
extends: ["eslint:recommended"]
}
]
};
Why teams use it:
- Clear separation between TS and JS files
- Faster linting
- Fewer parser errors
Pattern 2: Dedicated ESLint TypeScript config
Many teams create tsconfig.eslint.json so linting can include test files, scripts, or other files not used by the compiler.
{
"extends":
Common Mistakes
1. Using the TypeScript parser for every file
Broken example:
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json"
}
};
Why it breaks:
- ESLint applies the TypeScript project parser to all files, including
.jsconfig files.
How to avoid it:
- Use
overrides - Or ignore non-TypeScript files
2. Assuming extends does not affect parser behavior
Many configs such as Airbnb TypeScript presets bring in rules that need type information.
How to avoid it:
- Read the preset documentation
- Check whether it requires
parserOptions.project
3. Adding JavaScript files to tsconfig.json without understanding the effect
Possible fix, but not always ideal:
{
"include": [
Comparisons
| Approach | What it does | Best for | Pros | Cons |
|---|---|---|---|---|
ignorePatterns | Skips specific files entirely | Config files you do not care to lint | Simple | No linting on those files |
overrides | Uses different rules/parser settings per file type | Mixed TS and JS projects | Flexible and clean | Slightly more config |
tsconfig.eslint.json | Creates a special TS project for linting | Projects needing typed linting across more files | Keeps compiler config separate | Extra file to maintain |
Add files to tsconfig.json | Expands the main TS project |
Cheat Sheet
// Type-aware TypeScript ESLint setup
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json"
}
};
Key rule
If parserOptions.project is used, every linted file must:
- be included in the referenced TypeScript config
- or be ignored
- or be handled by an override without
project
Common fixes
// Ignore file
ignorePatterns: ["babel.config.js"]
// Disable project mode for specific files
overrides: [
{
files: ["*.js", "*.config.js"],
parserOptions: {
project: null
}
}
]
// Use a dedicated ESLint TS config
parserOptions: {
project: "./tsconfig.eslint.json"
}
FAQ
Why does ESLint complain about babel.config.js in a TypeScript project?
Because ESLint is using the TypeScript parser in project mode, and babel.config.js is usually not included in tsconfig.json.
What does parserOptions.project do?
It tells @typescript-eslint/parser to load a TypeScript project so ESLint can run rules that require type information.
Should I add babel.config.js to tsconfig.json?
Usually not. It is often better to ignore it, use an override, or create tsconfig.eslint.json.
What is the best fix for most projects?
Use overrides so TypeScript files use project-based linting and JavaScript config files do not.
Can I lint JavaScript and TypeScript files in the same project?
Yes. This is very common. You usually configure different parser options or rule sets for different file patterns.
Why did this start after extending an Airbnb TypeScript config?
Because TypeScript-focused shared configs often expect type-aware linting and may rely on parserOptions.project.
What is tsconfig.eslint.json used for?
Mini Project
Description
Create an ESLint setup for a small React Native TypeScript project that includes both application code and JavaScript config files. The goal is to avoid parserOptions.project errors while keeping strong linting for TypeScript files.
Goal
Configure ESLint so .ts and .tsx files use type-aware linting, while babel.config.js is linted safely without causing project inclusion errors.
Requirements
- Create an ESLint configuration that uses
@typescript-eslint/parserfor TypeScript files. - Apply
parserOptions.projectonly where type-aware linting is needed. - Ensure
babel.config.jsdoes not trigger the project config parsing error. - Keep the setup practical for a React Native codebase.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.
Angular @ViewChild Returning Undefined: Lifecycle, Child Components, and Fixes
Learn why Angular @ViewChild can be undefined, when it becomes available, and how to access child components correctly using lifecycle hooks.