Linting with ESLint

A linter is a tool that analyzes your code for potential errors, stylistic issues, and suspicious patterns. It does this without running the code. ESLint is the standard linter in the JavaScript ecosystem. It catches things like undeclared variables, or an accidental == where you meant ===.

Setting Up ESLint

Use ESLint’s official config wizard:

npm init @eslint/config@latest

The wizard asks about your environment (browser, Node, or both), your preferred style, and creates a config file for you. (npx eslint --init works in many setups as a shortcut.)

Configuring ESLint with Flat Config

ESLint 9+ uses a flat config format in eslint.config.js. This replaces the older .eslintrc.* files:

// eslint.config.js
import js from "@eslint/js";

export default [
  js.configs.recommended,
  {
    rules: {
      "no-unused-vars": "warn",
      "no-console": "off",
      eqeqeq: "error",
    },
  },
];

You start with js.configs.recommended (a set of default rules) and then override individual rules as needed.

Rule Severity

Every rule has three severity levels:

Level Numeric Meaning
"off" 0 Rule is disabled
"warn" 1 Shows a warning but does not fail the build
"error" 2 Fails the build

My advice is to use "error" for rules that catch real bugs (like eqeqeq) and "warn" for stylistic preferences (like no-console) that you want to eventually clean up.

Common Rules

Here are some rules you will see in most configurations:

{
  rules: {
    // Catch real bugs
    "no-debugger": "error",        // no leftover debugger statements
    "no-duplicate-case": "error",  // no duplicate switch cases
    "eqeqeq": "error",            // require === and !==
    "no-eval": "error",           // no eval() -- it is a security risk

    // Encourage modern style
    "prefer-const": "warn",        // use const when variable is never reassigned
    "no-var": "error",             // use let/const instead of var
    "prefer-arrow-callback": "warn", // prefer arrow functions as callbacks

    // Keep things tidy
    "no-unused-vars": "warn",      // flag variables that are declared but unused
    "curly": "error",              // require braces around control statements
  }
}

Running ESLint

You can run ESLint directly with npx:

npx eslint src/              # lint all files in src/
npx eslint src/ --fix         # lint and auto-fix what it can
npx eslint src/app.js         # lint a specific file

The --fix flag fixes many issues automatically, like adding a missing semicolon or switching var to let. Not all rules are auto-fixable. ESLint will report the rest for you to fix manually.

For convenience, add scripts to your package.json:

{
  "scripts": {
    "lint": "eslint src/",
    "lint:fix": "eslint src/ --fix"
  }
}

Ignoring Files and Directories

Some files should not be linted – build output, minified files, node_modules, etc. In flat config, use the ignores property:

export default [
  {
    ignores: ["dist/**", "node_modules/**", "*.min.js"],
  },
];

Disabling Rules with Inline Comments

Sometimes you have a legitimate reason to break a rule on specific lines of code. ESLint lets you disable rules with special comments:

// Disable a rule for the next line only
// eslint-disable-next-line no-console
console.log("debugging this one thing");

/* eslint-disable no-console */
// Everything below this is exempt from the no-console rule
console.log("first");
console.log("second");
/* eslint-enable no-console */