P

Paul Ching

A modern flat ESLint configuration for ESLint V9

P
Paul Ching2025/3/14 00:35:02
Star on GitHub

ESLint v9.0.0 is a major release of ESLint, it has several breaking changes, the biggest of which is the use of its configuration files and plugin ecosystem. You can learn how to migrate through the official website's Migrate to v9.x document.

Here is an npm package for ESLint V9's flat configuration, which has some of my favorite ESLint configurations built in. This is also an open source project I published on GitHub. If it helps you, please give it a Star !

A modern flat ESLint configuration for ESLint V9, crafted by @chengpeiquan.

⚡ Usage

Using this ESLint configuration only requires three steps:

  1. Install dependencies (See: 🚀 Installation)
  2. Add ESLint configuration file (See: 📂 Configuration File)
  3. Enable automatic Lint for VS Code settings.json (See: 🛠 VS Code Setup)

This quick guide helps you get up and running without missing key steps 🚀 .

🚀 Installation

Install the package with your favorite package manager:

npm install -D eslint @bassist/eslint-config

Note: Requires ESLint >= 9.0.0 , and TypeScript >= 5.0.0 .

If you’re using pnpm, consider adding a .npmrc file to your project root with the following settings to handle peer dependencies more smoothly:

shamefully-hoist=true
auto-install-peers=true

For ESLint v8 users, refer to the legacy (unmaintained) package: @bassist/eslint.

📂 Configuration File

Create an eslint.config.js file at the project root:

// eslint.config.js
import { imports, typescript } from '@bassist/eslint-config'

// export an array of configuration objects
export default [...imports, ...typescript]

Then add "type": "module" to your package.json:

{
  "type": "module",
  "scripts": {
    "lint": "eslint src",
    "lint:inspector": "npx @eslint/config-inspector"
  }
}

Run npm run lint to lint your code, or npm run lint:inspector to visualize your ESLint config at http://localhost:7777.

For typescript file type (e.g. eslint.config.ts ), requires additional setup .

# Runtime typescript and ESM support for Node.js
npm install -D jiti

✅ Type-Safe Config

For enhanced type safety, use defineFlatConfig:

// @ts-check
import { defineFlatConfig, imports, vue } from '@bassist/eslint-config'

export default defineFlatConfig([
  ...imports,
  ...vue,
  // Add more custom configurations
  {
    // Provide a name for each configuration so that
    // it can be clearly displayed in the visualizer
    // when running `npm run lint:inspector`.
    name: 'my-custom-rule/vue',
    rules: {
      // e.g. By default, this rule is `off`
      'vue/component-tags-order': 'error',
    },
    ignores: ['examples'],
  },
])

🛠 VS Code Setup

Enable automatic linting and fixing in VS Code by adding the following to your workspace settings:

{
  "editor.formatOnSave": true,
  "eslint.useFlatConfig": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "always",
    "source.fixAll.prettier": "always"
  }
}

📘 API Reference

defineFlatConfig

Define ESLint configurations with optional Prettier and Tailwind CSS integration.

The API type declaration:

/**
 * Define the ESLint configuration with optional Prettier integration.
 *
 * @param configs The base ESLint configurations.
 * @param options - Options for defining the configuration.
 *
 * @returns The final ESLint configuration array.
 */
declare const defineFlatConfig: (
  configs: FlatESLintConfig[],
  options?: DefineFlatConfigOptions,
) => FlatESLintConfig[]

The options type declaration:

interface DefineFlatConfigOptions {
  /**
   * Specifies the working directory for loading the `.prettierrc`
   * configuration.
   *
   * The config file should be in JSON format.
   *
   * @default process.cwd()
   */
  cwd?: string

  /**
   * If `prettierEnabled` is set to `false`, all Prettier-related rules and
   * configurations will be ignored, even if `prettierRules` are provided.
   *
   * @default true
   */
  prettierEnabled?: boolean

  /**
   * By default, this will read `.prettierrc` from the current working
   * directory, and the `.prettierrc` file must be written in JSON format.
   *
   * If you are not using a config file with JSON content, or a different config
   * file name, you can convert it to JSON rules and pass it in.
   *
   * After reading the custom configuration, it will be merged with the default
   * ESLint rules.
   *
   * @see https://prettier.io/docs/configuration.html
   */
  prettierRules?: PartialPrettierExtendedOptions

  /**
   * Tailwindcss rules are enabled by default. If they interfere with your
   * project, you can disable them with this option.
   *
   * @default true
   */
  tailwindcssEnabled?: boolean

  /**
   * If you need to override the configuration, you can pass the corresponding
   * options.
   *
   * If you want to merge configurations, you can import
   * `defaultTailwindcssSettings`, merge them yourself, and then pass the result
   * in.
   *
   * If an empty object `{}` is passed, the default settings will be used.
   */
  tailwindcssSettings?: TailwindcssSettings
}

createGetConfigNameFactory

createGetConfigNameFactory is a flexible tool function for generating ESLint configuration naming tools. It helps you quickly splice configuration names, ensure consistent namespaces, and facilitate the organization and management of complex rule sets.

The API type declaration:

/**
 * A flexible tool function for generating ESLint configuration naming tools. It
 * helps you quickly splice configuration names, ensure consistent namespaces,
 * and facilitate the organization and management of complex rule sets.
 *
 * @param prefix - A string representing the prefix for your configuration
 *   names.
 * @returns A function that concatenates the provided name segments with the
 *   given prefix.
 */
declare const createGetConfigNameFactory: (
  prefix: string,
) => (...names: string[]) => string

Usage:

import {
  createGetConfigNameFactory,
  defineFlatConfig,
} from '@bassist/eslint-config'

const getConfigName = createGetConfigNameFactory('my-prefix')

export default defineFlatConfig([
  {
    name: getConfigName('ignore'), // --> `my-prefix/ignore`
    ignores: ['**/dist/**', '**/.build/**', '**/CHANGELOG.md'],
  },
])

Why Use This?

  • Consistency: Enforces a clear and uniform naming pattern for your configurations.
  • Flexibility: Allows custom prefixes for different projects or scopes.
  • Simplified Management: Makes it easier to organize and navigate large ESLint configurations.

This utility is especially helpful when building reusable ESLint configurations or maintaining a well-structured ruleset for complex projects.

Exported Configurations

These are mainly the ones I use frequently. If you need any additions, welcome PR!

Languages

Frameworks

Formatters

Formatting rules are enabled by default and not exported externally. Please pass custom configuration via options of defineFlatConfig API .

  • Prettier : By default, the contents of .prettierrc and .prettierignore are read and added to ESLint rules.
  • Tailwind CSS : By default, tailwind.config.js is passed as the Tailwind CSS configuration file.

Others

📚 Migration Notes

  • Flat configs are unsupported in ESLint < 8.x.
  • The --ext CLI option is no longer available (#16991).

📝 Release Notes

Please refer to CHANGELOG for details.