ESLint statically analyzes JavaScript and TypeScript code to find bugs, enforce coding conventions, and suggest improvements, with the new flat config system using eslint.config.js for simpler, more composable rule configuration.
ESLint catches bugs like unused variables, unreachable code, and unsafe patterns at development time without executing the code.
eslint.config.js exports an array of config objects with files, rules, and plugins — replacing the legacy cascading .eslintrc format with predictable array-order application.
Rules set to 'off' are disabled, 'warn' flags issues without failing CI, and 'error' blocks builds — enabling gradual migration strategies.
The TypeScript ESLint plugin uses type information from the compiler to power rules that detect floating promises, unsafe assertions, and type-aware patterns.
ESLint is the standard static analysis tool for JavaScript and TypeScript. It examines your code without running it, catching common errors like unused variables, unreachable code, type coercion bugs, and accessibility issues. Properly configured ESLint catches bugs that would otherwise only be discovered at runtime or during testing.
ESLint rules fall into several categories: Possible Problems detect code that is likely buggy (using a variable before declaration, duplicate case labels, unreachable code after return). Suggestions recommend alternative patterns (prefer const over let when the variable is never reassigned, prefer template literals over string concatenation). Layout rules enforce formatting (now mostly handled by Prettier instead). The most valuable rules are those that catch genuine bugs — like no-unsafe-optional-chaining which catches (obj?.method)() patterns that will throw if obj is nullish.
ESLint 9 introduced flat config as the default, replacing the legacy .eslintrc format. Flat config uses a JavaScript file that exports an array of configuration objects. Each object can specify files (glob patterns for which files the config applies to), rules (rule configurations), plugins (plugin objects), and languageOptions (parser, globals, ecmaVersion). This is simpler and more predictable than the legacy cascading config system because there is no merging ambiguity — configs are applied in array order.
Each rule can be set to off (0), warn (1), or error (2). Some rules accept additional options as a second array element: ["error", { "allowConstantExport": true }]. The difference between warn and error is significant in CI — warnings do not fail the build, errors do. A common strategy is to use warn during migration and error for enforced standards.
eslint:recommended enables rules that catch common mistakes. @typescript-eslint/recommended adds TypeScript-specific rules that leverage type information (like detecting unused variables that TypeScript itself does not flag). Framework-specific configs like eslint-plugin-react-hooks enforce the Rules of Hooks. eslint-config-next bundles Next.js-specific rules for accessibility, performance, and framework conventions.
Plugins add new rules. The TypeScript ESLint plugin is nearly universal — it uses the TypeScript compiler's type information to power rules that plain ESLint cannot support (like detecting floating promises or unsafe type assertions). Parsers tell ESLint how to read non-standard syntax — @typescript-eslint/parser handles TypeScript, and @babel/eslint-parser handles experimental JavaScript features.
Many ESLint rules are auto-fixable with --fix. Auto-fixable rules handle safe, unambiguous transformations like converting var to let/const, adding missing semicolons, or sorting imports. More complex fixes are offered as "suggestions" that require manual confirmation because they might change behavior.
ESLint is static analysis — it examines code structure without executing it. This makes it fast and safe to run on every file save, but it cannot detect runtime errors, logic bugs, or issues that depend on actual data. Combining ESLint with TypeScript (for type safety) and testing (for behavior verification) creates a comprehensive code quality strategy.
Fun Fact
ESLint was created by Nicholas Zakas in 2013 because JSHint (the dominant linter at the time) did not support custom rules. The name 'ESLint' combines 'ES' (ECMAScript) with 'Lint' — a term that originated from a 1978 Unix utility that checked C code for suspicious constructs, named after the bits of fiber that collect in your clothes dryer.