Skip to content
sqlstack-ioPublic

About

Fast, opinionated SQL linting and deterministic formatting

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

SQLClean

The fastest SQL linter.

50× faster than sqruff. Lint 10,000 SQL files in under a second. Benchmarks
Website · Get started · Docs · Benchmarks

Catch SQL mistakes, apply safe fixes, and format consistently. Add your own rules in Python. SQLClean parses and checks SQL in Rust, and runs your Python Rules on statements it has already parsed.

uv tool install sqlclean        # or: pip install sqlclean

sqlclean check reports an unused CTE, a case-sensitive email comparison from a custom Rule and a comparison with NULL; sqlclean fix removes the CTE and formats the file; sqlclean fix --unsafe-fixes rewrites = NULL to IS NULL

sqlclean check reports an unused CTE, a case-sensitive email comparison that a team's custom Rule forbids, and a = NULL comparison that is never true. sqlclean fix applies the safe fix, removing the CTE, and formats the file. It leaves = NULL alone because rewriting it to IS NULL changes which rows match; sqlclean fix --unsafe-fixes applies that fix. The custom Rule only reports, so its finding stays.

Quick start

sqlclean check     # report findings in every .sql file under the directory
sqlclean fix       # apply safe fixes, then format
sqlclean format    # rewrite files in the canonical layout

Add a sqlclean.toml to choose a dialect, files or Rules. See the quickstart and configuration.

Speed

Linting the same 10,282 Snowflake SQL files on a Linux machine with 4 CPUs, each tool with its default rules and no cache:

Tool Wall time
sqlclean check 0.81 s
sqruff lint 41.0 s
sqlfluff lint --processes 4 919 s

The tools don't check the same things: almost every sqruff and SQLFluff finding comes from a layout rule, which SQLClean leaves to its formatter. See the benchmarks for coverage, the corpus, the method and how to run it yourself.

SQLClean in other configurations, on the same files:

SQLClean command Wall time
sqlclean check --select SQLCLEAN (every built-in Rule) 1.33 s
sqlclean check plus three custom Python Rules 2.27 s
sqlclean check rerun with nothing changed (result cache) 0.23 s

Correct and safe

  • Rules for SQL that runs but is wrong. Built-in Rules flag comparisons with NULL, NOT IN lists that contain NULL, ROW_NUMBER with no deterministic order and more. See Rules.
  • Safe fixes by default. sqlclean fix applies safe fixes only. A fix that can change which rows match waits for --unsafe-fixes, and a fix that would break parsing is discarded. See sqlclean fix.
  • An idempotent formatter. Every statement gets one canonical layout, and formatting a formatted file changes nothing. See formatting.

Custom Rules in Python

A custom Rule is a Python function over each statement, already parsed and located by the Rust engine. This team uses COALESCE instead of IFNULL to keep queries portable. The Rule reads function facts, not SQL text, so comments and string literals don't match. It only reports; the author chooses the replacement.

# sql_rules/team.py
from sqlclean import Finding, RuleContext, Statement, rule


@rule(
    code="XSQLCLEANTEAM001",
    message="Use COALESCE instead of IFNULL",
    remediation="Write COALESCE(value, fallback).",
    enabled_by_default=True,
)
def prefer_coalesce(*, statement: Statement, ctx: RuleContext) -> list[Finding]:
    return [
        ctx.finding(subject=statement, node=function)
        for function in statement.functions
        if function.name.upper() == "IFNULL"
    ]

Point [rules] custom = ["sql_rules"] in sqlclean.toml at it, then run sqlclean check:

SELECT IFNULL(discount, 0) FROM orders;
error[XSQLCLEANTEAM001]: Use COALESCE instead of IFNULL
  --> orders.sql:1:8
   |
 1 | SELECT IFNULL(discount, 0) FROM orders;
   |        ^^^^^^
  = help: Write COALESCE(value, fallback).

No extra dependencies are needed. See custom Rules, statement facts and testing custom Rules.

Integrations

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/sqlstack-io/sqlclean
    rev: v0.1.0
    hooks:
      - id: sqlclean-fix
      - id: sqlclean-format

Use sqlclean-check where a hook must not change files. In CI, sqlclean check exits non-zero on findings and writes SARIF with --output-format sarif for code-scanning annotations. See integrations. sqlclean skills installs a skill for AI coding agents; see sqlclean skills.

Docs

Development

uv sync --all-groups   # builds the native executable into .venv
make check             # format, lint, type-check, fensu and clippy
make test              # Rust and Python tests

License

Apache License 2.0.

About

Fast, opinionated SQL linting and deterministic formatting

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages