Linting Rules
Relevant source files
The following files were used as context for generating this wiki page:
Linting Rules in SQLFluff identify violations of coding standards and provide automated fixes for SQL source code. Rules operate on a complete parse tree generated after the templating, lexing, and parsing stages. Each rule exists as a Python class inheriting from BaseRule, utilizing specific crawlers to traverse segments and return LintResult objects containing descriptions and optional LintFix instructions.
Sources: docsv/development/architecture.md:95-107, docsv/development/developing-rules.md:3-9
Rule Architecture and Lifecycle
Rules follow a structured evaluation cycle within the linter. The linter crawls the parse tree and calls the _eval() method of each rule for specific segments.
Core Classes
| Class | Description |
|---|---|
BaseRule | The foundation for all rules. Defines metadata like code, name, and crawl_behaviour. |
RuleContext | Provides the environment for rule evaluation, including the current segment, parent stack, and dialect. |
LintResult | Represents a found violation. It contains an anchor (where the error is shown) and optional fixes. |
LintFix | Describes a specific change (edit, insert, or delete) to the parse tree to resolve a violation. |
Sources: src/sqlfluff/core/rules/base.py:284, docsv/development/architecture.md:104-107, docsv/scripts/generate-internals-docs.py:102-109
Execution Flow
The following diagram illustrates how a rule interacts with the parse tree during the linting process.
The linter uses a crawler to determine when to trigger the _eval() method. Rules can either check every segment or only the root.
Sources: docsv/development/developing-rules.md:20-30, docsv/development/custom-rules.md:17-30
Traversal and Crawlers
Crawlers control how a rule moves through the parse tree. Efficient crawling prevents unnecessary performance overhead on large SQL files.
- SegmentSeekerCrawler: The most common crawler. It calls
_eval()only for specific segment types (e.g.,keywordorselect_statement). - RootOnlyCrawler: Calls
_eval()exactly once for the rootFileSegment. This is used for rules that need a global view of the file, such as checking for trailing newlines. - provide_raw_stack: When set to
True, this gives rules access toRuleContext.raw_stackto see previous segments, though it increases overhead.
Sources: docsv/development/developing-rules.md:20-30, src/sqlfluff/core/rules/crawlers.py:16-118
Rule Phases
SQLFluff executes rules in two distinct phases to improve performance and handle cascading fixes:
- Main Phase: Used for most rules. These rules may trigger multiple passes (up to the
runaway_limit, default 10) as fixes from one rule may cause new violations in another. - Post Phase: Used for post-processing rules like capitalization. These run at the very end and are limited to 2 passes (one to fix, one to confirm).
Sources: docsv/development/developing-rules.md:52-65
Configuration and Selection
Users control rule application via .sqlfluff configuration files using the rules and exclude_rules settings.
Selection Logic
Rules can be referenced by their unique code (e.g., LT01), their name (e.g., layout.indent), or their group (e.g., core, layout).
rules: Explicitly enables a specific set of rules. If empty, all rules are enabled.exclude_rules: Disables specific rules. This is applied after therulesselection.warnings: Downgrades violations to warnings. The CLI will report them but will not return a failure exit code.
Sources: docsv/configuration/rules.md:23-52, docsv/configuration/rules.md:104-118
Configuration Hierarchy
SQLFluff merges configuration files based on proximity to the file being linted.
Files closer to the source file override values in parent directories.
Sources: docsv/configuration/index.md:94-110
Implementation Example
Developers define rules by specifying metadata and implementing the evaluation logic.
from sqlfluff.core.rules import BaseRule, LintResult, LintFix, RuleContext
from sqlfluff.core.rules.crawlers import SegmentSeekerCrawler
class Rule_EXAMPLE(BaseRule):
"""Keywords must be uppercase."""
groups = ("all", "core")
# Trigger only on keywords
crawl_behaviour = SegmentSeekerCrawler({"keyword"})
def _eval(self, context: RuleContext):
if context.segment.raw != context.segment.raw.upper():
return LintResult(
anchor=context.segment,
fixes=[LintFix.replace(context.segment, [context.segment.edit(context.segment.raw.upper())])]
)
return None
Sources: src/sqlfluff/AGENTS.md:108-132, docsv/development/custom-rules.md:32-47
Custom Rules and Plugins
The project supports organisation-specific rules via a plugin architecture. SQLFluff uses pluggy for discovery. For a custom rule to be detected, it must be installed as a Python package and define a sqlfluff entry point in its pyproject.toml or setup.py.
Sources: docsv/development/custom-rules.md:70-85
Linting rules represent the primary mechanism for enforcing SQL standards in SQLFluff. By leveraging specialized crawlers and a multi-phase execution model, the system balances technical depth with performance, allowing for both simple stylistic checks and complex structural transformations.