Flat config — это новый подход к конфигурации ESLint, в котором
вместо каскадного наследования и множества конфигурационных файлов
используется единый массив конфигурационных объектов. Основная точка
входа — файл eslint.config.js (или
eslint.config.mjs), который полностью заменяет классические
.eslintrc.*.
Ключевая идея flat config заключается в том, что конфигурация становится линейной, явной и предсказуемой: порядок объектов в массиве напрямую определяет приоритет и область действия правил.
Flat config представляет собой JavaScript-модуль, который экспортирует массив:
export default [
{
files: ["**/*.js"],
rules: {
semi: ["error", "always"],
quotes: ["error", "single"]
}
}
];
Каждый объект массива описывает отдельный слой конфигурации. ESLint применяет их последовательно, объединяя параметры.
Flat config полностью отказывается от концепции “extends” в классическом виде. Вместо этого используется:
filesПрименение правил происходит сверху вниз:
export default [
{
rules: {
quotes: ["error", "single"]
}
},
{
rules: {
quotes: ["error", "double"]
}
}
];
Итоговое правило — double, так как второй объект
перекрывает первый.
Ключ files задаёт, к каким файлам применяется
конфигурационный объект.
export default [
{
files: ["src/**/*.js"],
rules: {
semi: ["error", "always"]
}
},
{
files: ["test/**/*.js"],
rules: {
semi: ["off"]
}
}
];
Файлы сопоставляются по glob-шаблонам. Если files не
указан, конфигурация считается глобальной.
В flat config игнорирование встроено в саму систему:
export default [
{
ignores: ["dist/**", "node_modules/**"]
}
];
Особенность заключается в том, что ignores может
находиться в любом конфигурационном объекте и влияет на все последующие
правила.
Допускается глобальное игнорирование без files:
export default [
{
ignores: ["coverage/**"]
},
{
files: ["**/*.js"],
rules: {
no-console: "warn"
}
}
];
В классическом ESLint использовались parserOptions,
env, globals. В flat config они объединены в
languageOptions.
export default [
{
languageOptions: {
ecmaVersion: 2023,
sourceType: "module",
globals: {
window: "readonly",
document: "readonly"
}
}
}
];
Парсер задаётся явно:
import babelParser from "@babel/eslint-parser";
export default [
{
languageOptions: {
parser: babelParser
}
}
];
Поле rules работает аналогично классическому ESLint, но
без наследования через extends.
export default [
{
rules: {
eqeqeq: "error",
curly: ["error", "all"],
"no-unused-vars": "warn"
}
}
];
При конфликте правил действует принцип последнего применённого объекта.
Flat config больше не использует строковые идентификаторы плагинов. Плагины импортируются как модули.
import js from "@eslint/js";
import react from "eslint-plugin-react";
export default [
js.configs.recommended,
{
plugins: {
react
},
rules: {
"react/jsx-uses-react": "error"
}
}
];
Ключевой момент: plugin становится объектом, а не строкой.
Многие пакеты ESLint теперь экспортируют flat-конфиги напрямую:
import js from "@eslint/js";
export default [
js.configs.recommended
];
Это заменяет привычные:
extends: "eslint:recommended"extends: "plugin:react/recommended"Flat config использует строгий порядок:
Пример:
export default [
{
rules: {
semi: "error"
}
},
{
files: ["test/**"],
rules: {
semi: "off"
}
}
];
Для тестовых файлов правило semi отключается
полностью.
Flat config поддерживает модульную структуру:
import base from "./eslint.base.js";
import node from "./eslint.node.js";
import react from "./eslint.react.js";
export default [
...base,
...node,
...react
];
Каждый файл экспортирует массив конфигураций.
Flat config заменяет несколько фундаментальных механизмов:
Вместо цепочек:
{
"extends": ["eslint:recommended", "plugin:react/recommended"]
}
используется:
export default [
js.configs.recommended,
react.configs.flat.recommended
];
"env": { "browser": true }
заменяется на:
languageOptions: {
globals: {
window: "readonly",
document: "readonly"
}
}
Вместо:
{
"overrides": [
{
"files": ["*.test.js"],
"rules": {}
}
]
}
используется отдельный объект:
export default [
{
files: ["*.test.js"],
rules: {}
}
];
Для улучшения типизации и читаемости применяется вспомогательная функция:
import { defineConfig } from "eslint/config";
export default defineConfig([
{
rules: {
quotes: ["error", "single"]
}
}
]);
Она не меняет поведение, но улучшает автодополнение и проверку структуры.
Flat config ориентирован на ESM:
export default [...]
Однако возможна и CommonJS-форма:
module.exports = [
{
rules: {
semi: "error"
}
}
];
ESM считается основным сценарием, особенно при использовании плагинов
через import.
import js from "@eslint/js";
import react from "eslint-plugin-react";
import globals from "globals";
export default [
js.configs.recommended,
{
languageOptions: {
ecmaVersion: 2023,
sourceType: "module",
globals: globals.browser
},
rules: {
"no-console": "warn"
}
},
{
files: ["src/**/*.{js,jsx}"],
plugins: { react },
rules: {
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error"
}
},
{
files: ["**/*.test.js"],
rules: {
"no-console": "off"
}
}
];
Каждый объект конфигурации рассматривается как независимый слой. ESLint выполняет:
fileslanguageOptionsrules с приоритетом последнего
значенияignores до анализа файловКонфликтующие поля разрешаются через:
ignores имеет приоритет над files. Даже
если файл соответствует files, он исключается при
совпадении с ignores.
export default [
{
ignores: ["src/legacy/**"]
},
{
files: ["src/**/*.js"],
rules: {
strict: "error"
}
}
];
Файлы в src/legacy полностью исключаются из анализа.
Некоторые плагины продолжают поддерживать только legacy-конфигурации. Для них используется адаптер:
import compat from "@eslint/eslintrc";
const { FlatCompat } = compat;
const compatInstance = new FlatCompat();
export default [
...compatInstance.config({
extends: ["plugin:react/recommended"]
})
];
Это механизм переходного периода между системами конфигурации.
Flat config устраняет неоднозначность каскадирования:
Каждое правило определяется конкретным объектом массива и его позицией.
Если несколько объектов задают languageOptions,
происходит частичное объединение:
export default [
{
languageOptions: {
ecmaVersion: 2022
}
},
{
languageOptions: {
sourceType: "module"
}
}
];
Итог:
Flat config часто организуется слоями:
Каждый слой — отдельный объект или импортируемый массив.
Если files не указан:
export default [
{
rules: {
"no-debugger": "error"
}
}
];
Это правило действует повсеместно.