Configure Rules Effectively
ESLint rules are the foundation of code quality enforcement. This guide teaches you how to configure rules effectively for your team and project.
ESLint has over 280 built-in rules, and thousands more available via plugins.
Understanding Rule Basics
Rule Severity Levels
Every ESLint rule has a severity level that determines how violations are handled:
| Level | Value | Behavior |
|---|
| Off | "off" or 0 | Rule is disabled |
| Warn | "warn" or 1 | Violations logged as warnings (exit code 0) |
| Error | "error" or 2 | Violations logged as errors (exit code 1) |
Example:
export default [
{
rules: {
"no-unused-vars": "error", // Fails CI builds
"no-console": "warn", // Shows warning only
"no-alert": "off" // Completely disabled
}
}
];
Best Practice: Use "error" for critical issues, "warn" for code smells you’re gradually fixing, and "off" for rules that don’t apply to your project.
Basic Rule Configuration
Simple On/Off Rules
Many rules work as simple toggles:
export default [
{
files: ["**/*.js"],
rules: {
// Disallow var, prefer const/let
"no-var": "error",
// Require === instead of ==
"eqeqeq": "error",
// Disallow console statements
"no-console": "warn",
// Allow debugger in development
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off"
}
}
];
Rules with Options
Many rules accept configuration options:
export default [
{
rules: {
// Rule with single option
"quotes": ["error", "double"],
// Rule with multiple options
"comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "never",
"exports": "never",
"functions": "never"
}],
// Complex rule configuration
"no-unused-vars": ["error", {
"vars": "all",
"args": "after-used",
"ignoreRestSiblings": true,
"argsIgnorePattern": "^_"
}]
}
}
];
Check the rule documentation for available options. Each rule page includes a “Options” section.
Configuration Strategies
Using Presets
Start with recommended configurations and customize:
import js from "@eslint/js";
export default [
// Start with recommended rules
js.configs.recommended,
// Override specific rules
{
rules: {
"no-unused-vars": "warn", // Downgrade from error to warn
"no-console": "off" // Disable completely
}
}
];
Popular presets:
@eslint/js - ESLint recommended
eslint-config-airbnb - Airbnb style guide
eslint-config-standard - JavaScript Standard Style
@typescript-eslint/recommended - TypeScript rules
File-Specific Configuration
Apply different rules to different file types:
export default [
// Strict rules for production code
{
files: ["src/**/*.js"],
rules: {
"no-console": "error",
"no-debugger": "error",
"complexity": ["error", 10]
}
},
// Relaxed rules for tests
{
files: ["**/*.test.js", "**/*.spec.js"],
rules: {
"no-console": "off",
"max-lines-per-function": "off",
"max-nested-callbacks": "off"
}
},
// Config files can use require()
{
files: ["*.config.js"],
rules: {
"@typescript-eslint/no-require-imports": "off"
}
}
];
Environment-Based Configuration
Adjust rules based on environment:
const isProduction = process.env.NODE_ENV === "production";
const isDevelopment = !isProduction;
export default [
{
rules: {
// Strict in production, lenient in dev
"no-console": isProduction ? "error" : "warn",
"no-debugger": isProduction ? "error" : "off",
// Performance rules for production
"no-await-in-loop": isProduction ? "warn" : "off",
// Development helpers
"no-unused-vars": isDevelopment ? "warn" : "error"
}
}
];
Common Rule Patterns
Code Quality Rules
export default [
{
rules: {
// Prevent bugs
"no-unused-vars": "error",
"no-undef": "error",
"no-unreachable": "error",
"no-constant-condition": "error",
// Best practices
"eqeqeq": ["error", "always"],
"no-eval": "error",
"no-implied-eval": "error",
"prefer-const": "error",
"no-var": "error",
// Complexity limits
"complexity": ["warn", 15],
"max-depth": ["warn", 4],
"max-lines-per-function": ["warn", 50]
}
}
];
Style Consistency Rules
Many style rules are deprecated in favor of formatters like Prettier. Use ESLint for logic, Prettier for formatting.
export default [
{
rules: {
// Naming conventions
"camelcase": ["error", { "properties": "never" }],
// Modern syntax
"prefer-arrow-callback": "error",
"prefer-template": "error",
"object-shorthand": "error",
// Import organization
"sort-imports": ["error", {
"ignoreCase": true,
"ignoreDeclarationSort": true
}]
}
}
];
Security Rules
export default [
{
rules: {
// Prevent security issues
"no-eval": "error",
"no-implied-eval": "error",
"no-new-func": "error",
"no-script-url": "error",
// Safe regex
"no-invalid-regexp": "error",
"no-regex-spaces": "error",
// Prototype pollution
"no-proto": "error",
"no-extend-native": "error"
}
}
];
Advanced Configuration
Rule Cascading
Later configurations override earlier ones:
export default [
// Base config for all files
{
rules: {
"no-console": "error",
"no-unused-vars": "error"
}
},
// Override for test files (applied second)
{
files: ["**/*.test.js"],
rules: {
"no-console": "off" // Overrides the "error" above
}
}
];
Shared Configurations
Create reusable configs for your organization:
// configs/base.js
export const baseConfig = {
rules: {
"no-var": "error",
"prefer-const": "error",
"eqeqeq": "error"
}
};
// configs/typescript.js
export const typescriptConfig = {
files: ["**/*.ts"],
rules: {
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/explicit-function-return-type": "error"
}
};
// eslint.config.js
import { baseConfig } from "./configs/base.js";
import { typescriptConfig } from "./configs/typescript.js";
export default [
baseConfig,
typescriptConfig
];
Inline Configuration
Disable rules for specific lines or files:
// Disable for next line
// eslint-disable-next-line no-console
console.log("Debug info");
// Disable for current line
console.log("Debug"); // eslint-disable-line no-console
// Disable entire file
/* eslint-disable no-console */
console.log("This file uses console");
console.error("Errors too");
// Disable multiple rules
/* eslint-disable no-console, no-alert */
console.log("Multiple rules disabled");
alert("This too");
/* eslint-enable no-console, no-alert */
// Disable specific rule with reason
// eslint-disable-next-line no-await-in-loop -- Intentional: sequential API calls required
for (const item of items) {
await processItem(item);
}
Use inline disables sparingly. Excessive use indicates your base configuration may need adjustment.
Rule Configuration Examples
React Project Configuration
import js from "@eslint/js";
import react from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
export default [
js.configs.recommended,
react.configs.flat.recommended,
{
files: ["**/*.jsx", "**/*.tsx"],
plugins: {
react,
"react-hooks": reactHooks
},
rules: {
// React rules
"react/prop-types": "off", // Using TypeScript
"react/react-in-jsx-scope": "off", // React 17+
"react/jsx-uses-react": "off",
// Hooks rules
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
}
];
TypeScript Project Configuration
import js from "@eslint/js";
import tseslint from "@typescript-eslint/eslint-plugin";
import tsparser from "@typescript-eslint/parser";
export default [
js.configs.recommended,
{
files: ["**/*.ts", "**/*.tsx"],
languageOptions: {
parser: tsparser,
parserOptions: {
project: "./tsconfig.json"
}
},
plugins: {
"@typescript-eslint": tseslint
},
rules: {
// TypeScript-specific
"@typescript-eslint/no-unused-vars": ["error", {
"argsIgnorePattern": "^_"
}],
"@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/no-explicit-any": "warn",
// Disable base rule
"no-unused-vars": "off"
}
}
];
Node.js API Project Configuration
import js from "@eslint/js";
import globals from "globals";
export default [
js.configs.recommended,
{
files: ["**/*.js"],
languageOptions: {
globals: {
...globals.node
}
},
rules: {
// Node.js best practices
"no-console": "off", // Console is fine in Node
"no-process-exit": "error",
"handle-callback-err": "error",
// Async patterns
"no-return-await": "error",
"prefer-promise-reject-errors": "error",
// Security
"no-eval": "error",
"no-new-func": "error"
}
}
];
export default [
// Base rules for all packages
{
files: ["packages/**/*.js"],
rules: {
"no-var": "error",
"prefer-const": "error"
}
},
// Frontend package
{
files: ["packages/frontend/**/*.jsx"],
rules: {
"no-console": "error",
"react/prop-types": "off"
}
},
// Backend package
{
files: ["packages/backend/**/*.js"],
rules: {
"no-console": "off",
"no-process-env": "warn"
}
},
// Shared utilities
{
files: ["packages/shared/**/*.js"],
rules: {
"no-console": "error",
"complexity": ["error", 5]
}
}
];
Cache ESLint results
Caching speeds up subsequent runs significantly. Limit file scope
Only lint files you care about:export default [
{
files: ["src/**/*.js"],
ignores: ["src/**/*.test.js", "dist/**", "node_modules/**"]
}
];
Disable expensive rules
Some rules require type information (slower):rules: {
// Fast
"no-console": "error",
// Slow (requires type checking)
"@typescript-eslint/no-floating-promises": "off"
}
Use --max-warnings in CI
npx eslint --max-warnings 0 .
Fails the build if any warnings exist.
Debugging Rule Configuration
Use --debug flag to see which configs are applied:npx eslint --debug src/app.js
Print effective config for a file:
npx eslint --print-config src/app.js
Check which rules are enabled:
npx eslint --print-config src/app.js | grep rules -A 50
Best Practices
Start Strict
Enable strict rules early. It’s easier to relax than tighten later.
Document Decisions
Add comments explaining why rules are disabled or configured unusually.
Review Regularly
Audit your config quarterly. Remove obsolete rules and add new ones.
Team Consensus
Discuss rule changes with the team. Avoid surprise configuration updates.
Common Pitfalls
Pitfall #1: Too many disabled rulesIf you’re disabling many rules, you may be using the wrong preset.
Pitfall #2: Conflicting formattersDon’t use both ESLint formatting rules and Prettier. Choose one.
Pitfall #3: Environment mismatchEnsure your languageOptions.globals matches your runtime environment.
Resources
Rule Reference
Complete list of ESLint rules
Configuration Guide
Comprehensive configuration docs
Plugin Directory
Find ESLint plugins on npm
Awesome ESLint
Curated list of ESLint resources