跪拜 Guibai
← All articles
Frontend · Team Management

ESLint Flat Config from Zero: One File to End Team Style Wars

By YIAN ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Flat Config is now the default for new ESLint projects, and the old `.eslintrc` format is effectively legacy. Teams that don't migrate will hit editor integration breakage and miss out on the cleaner ESM-native authoring model that makes TypeScript and monorepo setups simpler.

Summary

ESLint 9.x+ officially pushes Flat Config (`eslint.config.mjs`) over the old `.eslintrc.js` format. The new approach exports a plain array of config blocks, uses native ESM imports, and registers plugins as objects instead of strings — making the config read more like a standard JS module and cutting down on nesting. A complete starter config pulls in `@eslint/js` for recommended JS rules, `globals` to declare browser globals, and `typescript-eslint` for TS support, then layers custom rules like `no-var` (error), `no-console` (warn), and enforced double quotes, semicolons, and 2-space indentation.

The setup pairs with VSCode's ESLint extension and `editor.codeActionsOnSave` to auto-fix formatting on every save. A critical flag — `"eslint.useFlatConfig": true` — must be set, or the editor ignores the new config file entirely. Common pitfalls include getting the filename exactly right, never using `module.exports` in `.mjs`, not omitting the spread operator on `...tseslint.configs.recommended`, and always declaring `globals.browser` to avoid `no-undef` errors on `window` and `document`.

For teams, the recommendation is a single shared config, combined with Prettier for formatting, enforced via `pnpm lint` in CI, and rolled out gradually with warn-level rules on legacy codebases to avoid a wall of errors.

Takeaways
The new Flat Config file must be named exactly `eslint.config.mjs`; any deviation and ESLint silently ignores it.
Configs export an array of blocks via `export default defineConfig([...])`, with later blocks overriding earlier ones.
Plugins are now imported as objects and registered in a `plugins` field before use — string names no longer work.
`globals.browser` from the `globals` package must be set in `languageOptions.globals`, otherwise `window` and `document` trigger `no-undef` errors.
The spread operator in `...tseslint.configs.recommended` is mandatory; dropping it breaks the TypeScript rule merge.
VSCode requires `"eslint.useFlatConfig": true` in `settings.json` to recognize the new config file.
`--fix` auto-corrects formatting rules like quotes, semicolons, and indentation but cannot fix logic issues like unused variables.
Set mandatory style rules to `error` (2) and advisory rules like `no-console` to `warn` (1) during development.
A single shared config, Prettier pairing, and a CI lint gate (`pnpm lint`) keep the whole team aligned without manual enforcement.
Conclusions

The Flat Config shift is as much about tooling compatibility as it is about syntax: VSCode's ESLint extension will silently ignore the new format unless a specific flag is toggled, which is an easy trap for teams upgrading.

ESLint's rule severity system (0/1/2) doubles as a rollout strategy — setting everything to `warn` on legacy projects lets a team adopt standards without blocking builds, then ratchet up to `error` over time.

The explicit `globals` declaration requirement in Flat Config surfaces a long-standing hidden assumption: old configs often worked because environments were inferred, but the new model forces teams to state exactly where their code runs.

Concepts & terms
Flat Config
ESLint's new configuration system (eslint.config.mjs) that replaces the legacy .eslintrc.* formats. It exports a flat array of config objects using native ESM syntax, with plugins imported directly as objects rather than referenced by string names.
defineConfig
A helper function imported from eslint/config that wraps the config array to provide TypeScript-style type hints and autocompletion when authoring ESLint configurations in editors.
globals (package)
An npm package that predefines global variables for different runtime environments (browser, node, worker, etc.). In Flat Config, it must be explicitly set in languageOptions.globals to prevent no-undef errors on environment-specific APIs like window or document.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗