ESlint V9 Flatconfig
This article starts with explanation on ESLint and deep dives into the flatConfig structure which is the default structure in ESLint V9
ESlint V9 Flatconfig
This article starts with explanation on ESLint and deep dives into the flatConfig structure which is the default structure in ESLint V9
ESLint
Eslint is a generic linting tool to find any problematic patterns in javascriptcode. It is used across javascriptframeworks and languages.
Supports multiple files including Javascript , Typescript, and JSX .
More info
Typescript ESLint
Typescript ESLint is an extension of ESLint specifically for Typescript . It provides Typescript specific linting rules built on top of ESLint .
Angular ESLint
Angular ESLint is a set of tools that enables ESLint for Angular projects. It combines ESLintrules along with Angular specific configuration and rules . It also provides Angular template linting capabilities.
Major features in ESLint V9
- Performance
— quiet flag now ignores execution on rules set to warn thus increasing the build time of the application.
- Simplicity
ESLint configuration is simplified with flat config structure which supports .cjs .mjs and .js as opposed to .yml , .json structure in their previous versions
Removed Properties:
Global ignoresPattern is replaced with ignores in individual config object
Plugins no longer take string based key-value pair. It is now an object configuration
Caveat: .mjsformat is not yet supported in NX (at the time of writing this article (Jan 2025)
Configuration for Angular project: (eslint.config.cjs)
const importPlugins = require('eslint-plugin-import');
const eslintTs = require('typescript-eslint');
const angular = require('angular-eslint');
const nx = require('@nx/eslint-plugin');
const unusedImportsPlugin = require('eslint-plugin-unused-imports');
const prettierPlugin = require('eslint-plugin-prettier');
const eslintPrettierPlugin = require('eslint-config-prettier');
const tsFiles = ['**/*.ts'];
const ignores = [
'/build/**',
'/reports/**',
'**/dist/**',
'**/node_modules/**',
'**/.storybook/**',
'jest.config.ts',
'!apps/demo/src/**/*.ts'
];
const languageOptions = {
globals: {
// add global env variables in future
}
}
const jsonConfig = {
files: ['**/*.json'],
// Override or add rules here
rules: {},
languageOptions: {
parser: require('jsonc-eslint-parser')
}
}
const tsConfig = {
files: tsFiles,
plugins: {
import: importPlugins,
'import/parser': eslintTs.parser,
'@nx': nx,
'unused-imports': unusedImportsPlugin,
prettier: prettierPlugin
},
languageOptions: {
...languageOptions,
parser: eslintTs.parser,
parserOptions: {
project: './tsconfig.eslint.json'
}
},
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts'],
},
},
rules: {
"unused-imports/no-unused-imports": "error",
'import/order': [
'error',
{
'groups': ["builtin", "external", "internal", "parent", "sibling", "index", "object", "type"]
}
],
'import/export': 'error',
'import/no-duplicates': 'warn',
...importPlugins.configs.typescript.rules,
'@typescript-eslint/no-use-before-define': 'off',
'require-await': 'off',
'no-duplicate-imports': 'error',
'no-unneeded-ternary': 'error',
'prefer-object-spread': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
ignoreRestSiblings: true,
args: 'none',
},
],
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'interface',
format: ['PascalCase'],
custom: {
regex: '^I[A-Z]',
match: false
}
},
{
selector: 'class',
format: ['PascalCase']
},
{
selector: 'typeAlias',
format: ['PascalCase'],
custom: {
regex: '^T[A-Z]',
match: false
}
}
],
// overriding rules provided by angular-eslint
'@angular-eslint/no-input-rename': 'off',
'@angular-eslint/component-class-suffix': 1,
'@angular-eslint/directive-class-suffix': 1,
'@angular-eslint/no-output-on-prefix': 'warn',
'@angular-eslint/no-output-native': 'warn',
'@nx/nx-plugin-checks': 'error',
...prettierPlugin.configs.recommended.rules,
...eslintPrettierPlugin.rules
}
}
// Add the files for applying the recommended TypeScript configs
// only for the Typescript files.
// This is necessary when we have the multiple extensions files
// (e.g. .ts, .tsx, .js, .cjs, .mjs, etc.).
const recommendedTypeScriptConfigs = [
...eslintTs.configs.recommended.map((config) => ({
...config,
files: tsFiles,
})),
...eslintTs.configs.stylistic.map((config) => ({
...config,
files: tsFiles,
}))
]
const recommendedAngularConfigs = [
...angular.configs.tsRecommended.map((config) => ({
...config,
files: tsFiles
})),
...angular.configs.templateRecommended.map((config) => ({
...config,
files: ['**/*.html'],
})),
...angular.configs.templateAccessibility.map((config) => ({
...config,
files: ['**/*.html']
}))
]
const recommendedNXConfigs = [
...nx.configs['flat/base'],
...nx.configs['flat/typescript'].map((config) => ({
...config,
files: tsFiles
})),
...nx.configs['flat/angular'].map((config) => ({
...config,
files: tsFiles
}))
]
module.exports = [
{ ignores }, // global ignores
...recommendedTypeScriptConfigs,
...recommendedAngularConfigs,
...recommendedNXConfigs, // all the typescript and angular rules gets overriden by NX specific typescript and angular rules
tsConfig,
jsonConfig
] 메타데이터
- post_id
- 8a4faa1059e6
- slug
- eslint-v9-flatconfig-8a4faa1059e6
- url
- https://medium.com/@sofiyanaidu/eslint-v9-flatconfig-8a4faa1059e6
- canonical_url
- https://medium.com/@sofiyanaidu/eslint-v9-flatconfig-8a4faa1059e6
- author_url
- https://medium.com/@sofiyanaidu
- status
- ok
- fetched_at
- 2026-07-28 16:12:54