Skip to main content

Custom Rules

Custom rules allow you to enforce code standards specific to your project. This guide shows you how to create, test, and distribute custom rules.

Rule Structure

Every rule is a JavaScript module that exports an object with two main properties:

The Meta Object

The meta object contains metadata about your rule:
type
string
required
Rule type: "problem", "suggestion", or "layout"
  • "problem": Code that will cause errors or confusing behavior
  • "suggestion": Code that could be improved but won’t cause errors
  • "layout": Whitespace, semicolons, and code formatting
docs
object
Documentation metadata
docs.description
string
required
Short description of what the rule does
Whether the rule is recommended
docs.url
string
URL to full documentation
fixable
string
Either "code" or "whitespace" if the rule supports automatic fixes
The fixable property is mandatory for fixable rules. Omit it if your rule doesn’t provide fixes.
hasSuggestions
boolean
Set to true if the rule provides suggestions
The hasSuggestions property is mandatory for rules that provide suggestions.
schema
array | object | false
JSON Schema defining the rule’s options. Mandatory when the rule has options.
messages
object
Object mapping message IDs to message templates

The Create Function

The create() function returns an object with visitor methods that ESLint calls while traversing the AST:
Visit ESLint Code Explorer to see the AST structure for any JavaScript code.

Real Example: no-console

Here’s a simplified version of ESLint’s no-console rule:

The Context Object

The context parameter provides essential information and methods:
context.id
string
The rule ID
context.filename
string
The filename being linted
context.sourceCode
SourceCode
Object to interact with the source code
context.options
array
Configured options for the rule (excludes severity)
context.settings
object
Shared settings from configuration
context.languageOptions
object
Language configuration (sourceType, ecmaVersion, parser, etc.)
context.report()
function
Reports a problem in the code

Reporting Problems

Use context.report() to report violations:

Using Message IDs

Message IDs are the recommended way to define messages:

Applying Fixes

Provide automatic fixes using the fix function:

Fixer Methods

fixer.insertTextAfter(nodeOrToken, text)
function
Insert text after a node or token
fixer.insertTextBefore(nodeOrToken, text)
function
Insert text before a node or token
fixer.remove(nodeOrToken)
function
Remove a node or token
fixer.replaceText(nodeOrToken, text)
function
Replace the text of a node or token
fixer.insertTextAfterRange(range, text)
function
Insert text after a range
fixer.insertTextBeforeRange(range, text)
function
Insert text before a range
fixer.removeRange(range)
function
Remove text in a range
fixer.replaceTextRange(range, text)
function
Replace text in a range

Fix Best Practices

Follow these guidelines when creating fixes:
  1. Don’t change runtime behavior - Fixes should only improve code style
  2. Make fixes small - Large fixes can conflict with other rules
  3. One fix per message - Return a single fix or array of fixes
  4. Don’t check for style conflicts - ESLint will re-run rules after fixes

Providing Suggestions

Suggestions are alternatives to automatic fixes that require user approval:

Accessing Source Code

The SourceCode object provides methods to work with the code:

Common SourceCode Methods

Returns the source code for a node
Returns the first token of a node
Returns tokens before a node
Returns comments before a node

Working with Options

Define a schema to validate rule options:

Accessing Variable Scopes

Track variables and their usage:

Creating Your First Rule

1

Define the Rule

Create a new file for your rule:
lib/rules/no-var.js
2

Test Your Rule

Create tests using RuleTester:
tests/rules/no-var.js
3

Use the Rule

Add to your ESLint configuration:
eslint.config.js

Testing Rules

Use RuleTester to validate your rule:

Runtime Rules

Test rules locally without publishing:
1

Create a rules directory

2

Add your rule file

3

Configure ESLint

eslint.config.js
4

Run with --rulesdir

Performance Tips

Rules run on every file. Follow these practices:
  • Target specific nodes: Only visit necessary node types
  • Avoid expensive operations: No file I/O or network requests
  • Cache results: Store computed values
  • Use early returns: Exit visitor methods quickly when possible

Profile Your Rule

Real-World Examples

Learn from ESLint’s built-in rules:

no-unused-vars

Complex scope analysis and variable tracking

semi

Automatic fixing and option handling

no-shadow

Scope traversal and variable shadowing

array-callback-return

Code path analysis

Next Steps

Create a Plugin

Package your rule for distribution

Learn About Selectors

Use advanced AST selectors

Scope Manager

Deep dive into scope analysis

Code Path Analysis

Analyze execution paths