ESLint Cheat Sheet

ESLint 9 flat config: eslint.config.js structure, rule severity, plugins, ignores, CLI usage, and auto-fix workflows.

Languages
eslint
linter
javascript

ESLint 9 ships the flat configuration format as the only supported style: a single eslint.config.js exporting an array of config objects. The legacy .eslintrc.* files still work but are deprecated, and the linter emits a warning at startup. New projects should start on flat config and never look back.

Flat config basics

A flat config is an ES module that exports either an array of config objects, a function that returns one, or — for libraries — a config object that callers can spread into their own array.

js
// eslint.config.js — flat config (ESLint 9+)
import js from "@eslint/js";

export default [
  js.configs.recommended,
  {
    files: ["**/*.{js,jsx,ts,tsx}"],
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      globals: {
        window: "readonly",
        document: "readonly",
        console: "readonly",
      },
    },
    rules: {
      "no-unused-vars": "warn",
      "eqeqeq": "error",
      "no-console": "warn",
    },
  },
];
Table
ConceptRole
filesGlobs that scope the config block
languageOptionsParser, ecma version, source type, globals
pluginsLoaded plugin instances (flat style: object in, not string)
rulesMap of rule id → severity or [severity, options]
ignoresGlobs the config does not apply to
settingsShared data accessible to rules

Flat configs are applied in declaration order — later blocks override earlier ones for matching files, so put general rules first and project-specific overrides last.

Rules and severity

Severity is the first argument to a rule, either a string or a number. Numeric values are kept for the migration story but the named forms are clearer in new configs.

js
{
  rules: {
    // string severity
    "no-unused-vars": "warn",
    "no-console": "error",

    // string + options
    "no-unused-vars": ["error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],

    // numeric severity (legacy form, still supported)
    "eqeqeq": 2,

    // disable
    "no-eval": "off",
  },
}
Table
SeverityMeaning
"off" / 0Rule disabled
"warn" / 1Reported as a warning, exit code still 0 unless --max-warnings
"error" / 2Reported as an error, non-zero exit code

Some rules accept a second argument with options — always check the rule's docs; the wrong option shape is the most common source of "rule didn't apply" surprises.

Plugins and language options

Plugins register namespaces that can later appear in rules and configs. In flat config the plugin is an object, not a string, and the namespace is whatever the plugin exports under meta.name.

js
import js from "@eslint/js";
import tsParser from "@typescript-eslint/parser";
import tsPlugin from "@typescript-eslint/eslint-plugin";
import reactPlugin from "eslint-plugin-react";

export default [
  js.configs.recommended,
  {
    files: ["**/*.ts", "**/*.tsx"],
    languageOptions: {
      parser: tsParser,
      parserOptions: {
        ecmaVersion: "latest",
        sourceType: "module",
      },
    },
    plugins: {
      "@typescript-eslint": tsPlugin,
      react: reactPlugin,
    },
    rules: {
      "@typescript-eslint/no-unused-vars": "warn",
      "react/jsx-key": "error",
    },
  },
];
Table
NeedPlugin / package
TypeScript parsing@typescript-eslint/parser
TypeScript-aware rules@typescript-eslint/eslint-plugin
React ruleseslint-plugin-react, eslint-plugin-react-hooks
Import orderingeslint-plugin-import
A11y on JSXeslint-plugin-jsx-a11y
Vue / Svelteeslint-plugin-vue, eslint-plugin-svelte

The meta.name of a plugin is what you use to prefix its rules in rules and in configs references; some plugins still document the npm package name and that mismatch is the #1 source of "rule not found" errors.

Useful rules to start with

These catch the majority of real bugs without becoming a style argument. Build a custom recommended once and reuse it across repos.

js
{
  rules: {
    // bugs
    "no-undef": "error",
    "no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
    "no-implicit-globals": "error",
    "no-fallthrough": "error",
    "no-return-await": "error",
    "require-await": "warn",

    // safety
    "eqeqeq": ["error", "always", { null: "ignore" }],
    "no-console": "warn",
    "no-debugger": "error",
    "no-eval": "error",

    // style (often turned off per project)
    "prefer-const": "warn",
    "no-var": "error",
    "object-shorthand": "warn",
  },
}
Table
CategoryExample rules
Likely bugsno-undef, no-unused-vars, no-fallthrough, no-dupe-keys
Modernizationprefer-const, prefer-template, no-var, object-shorthand
Safetyeqeqeq, no-eval, no-implied-eval, no-new-func
Stylequotes, semi, indent, comma-dangle

Ignoring files and sharing configs

In flat config, ignores lives inside any config object. Sharing a config means exporting an array (or a function that returns one) and having callers spread it.

js
{
  ignores: [
    "node_modules/**",
    "dist/**",
    "build/**",
    "coverage/**",
    ".next/**",
    "*.min.js",
  ],
}

To reuse logic across repos, export a function that takes options:

js
// eslint-config-myorg/index.js
import js from "@eslint/js";

export default function myorg(options = {}) {
  return [
    js.configs.recommended,
    {
      ignores: ["dist/**", "node_modules/**"],
    },
    {
      rules: {
        "no-console": options.allowConsole ? "off" : "warn",
      },
    },
  ];
}

Consumers spread the result into their own array:

js
import myorg from "eslint-config-myorg";

export default [
  ...myorg({ allowConsole: true }),
  // local overrides
];

Running the CLI

npx eslint . lints everything matched by your configs; --fix repairs what it can; --max-warnings turns warnings into a non-zero exit when you want a strict CI gate.

bash
# Lint everything in the project
npx eslint .

# Lint specific files or globs
npx eslint "src/**/*.ts"

# Auto-fix what can be fixed
npx eslint . --fix

# Fail the build when warnings exceed a threshold
npx eslint . --max-warnings 0

# Use a different config file
npx eslint . --config eslint.config.prod.mjs

# Inspect which config applies to a file
npx eslint --print-config src/index.ts
Table
FlagEffect
--fixApply automatic fixes where the rule supports them
--max-warnings NExit non-zero when warnings > N
--cacheSkip re-linting unchanged files
--cache-locationWhere to keep the cache file
--print-config pathDump the merged config for a file
--debugTrace rule loading and resolution
--extRemoved in flat config — use files in config

For editor integration, install the official ESLint VS Code extension and the linter runs on save with no extra setup.

References