How to Write a Custom ESLint Rule for Node.js

This article provides a practical, step-by-step guide to writing and implementing custom ESLint rules for Node.js applications. You will learn how ESLint uses Abstract Syntax Trees (ASTs) to analyze code, how to structure a rule file using the meta and create properties, and how to package your custom rule as a local plugin to enforce your team’s specific coding standards.

Step 1: Understand the Structure of an ESLint Rule

ESLint rules are written in JavaScript and export an object with two primary properties: meta and create.

Here is the basic boilerplate for a custom rule:

module.exports = {
  meta: {
    type: "suggestion", // "problem", "suggestion", or "layout"
    docs: {
      description: "Disallow the use of a specific variable name",
      category: "Stylistic Issues",
      recommended: false,
    },
    schema: [], // Defines configuration options if the rule accepts arguments
    messages: {
      avoidName: "Avoid naming variables 'temp'. Use descriptive names instead.",
    },
  },
  create(context) {
    return {
      // AST selector methods go here
    };
  },
};

Step 2: Identify the AST Nodes

ESLint parses your JavaScript code into an AST before analyzing it. To target specific code patterns, you must identify the corresponding AST node type. You can use online tools like AST Explorer (set the parser to “espree”) to paste your code and inspect the tree structure.

For example, if you write const temp = 1;, AST Explorer reveals that the name temp is represented by an Identifier node nested inside a VariableDeclarator.

Step 3: Write the Rule Logic

Using the boilerplate, you can target VariableDeclarator nodes to check if any variable is named “temp”. If a match is found, use context.report() to trigger an ESLint warning or error.

module.exports = {
  meta: {
    type: "suggestion",
    docs: {
      description: "Disallow naming variables 'temp'",
    },
    messages: {
      noTemp: "Do not use 'temp' as a variable name.",
    },
  },
  create(context) {
    return {
      VariableDeclarator(node) {
        if (node.id && node.id.name === "temp") {
          context.report({
            node: node.id,
            messageId: "noTemp",
          });
        }
      },
    };
  },
};

Step 4: Package the Rule as an ESLint Plugin

To use this rule in a Node.js project, you must expose it via an ESLint plugin.

  1. Create a directory named eslint-plugin-custom in your project’s root folder or as a separate local package.
  2. Inside that directory, create an index.js file.
  3. Export your custom rule inside a rules object:
const noTempRule = require("./rules/no-temp");

module.exports = {
  rules: {
    "no-temp": noTempRule,
  },
};

Step 5: Integrate the Plugin into Your Node.js Project

To load your local plugin, specify its path in your project’s package.json dependencies, or link to it locally.

In your project’s .eslintrc.js config file, add your plugin and configure the custom rule:

module.exports = {
  plugins: [
    // References 'eslint-plugin-custom' from your node_modules
    "custom" 
  ],
  rules: {
    // Enables your custom rule and sets it to trigger an error
    "custom/no-temp": "error" 
  }
};

When you run npx eslint ., ESLint will parse your files, execute your custom rule logic against the codebase, and flag any variable declarations named temp as errors.