Skip to main content

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.

Metadata

Release files for sqlclean 0.6.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sqlclean 0.6.2
File Size Uploaded Provenance Actions
sqlclean-0.6.2.tar.gz 2.2 MB With provenance Details for sqlclean-0.6.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for sqlclean 0.6.2
File Interpreter ABI Platform Actions
sqlclean-0.6.2-py3-none-any.whl Python 3 none any Details for sqlclean-0.6.2-py3-none-any.whl

Total release size: 2.3 MB

Release files / sqlclean-0.6.2.tar.gz

Download URL sqlclean-0.6.2.tar.gz
Size 2.2 MB
Tags Source
SHA-256 checksum
How to use checksums
e9fb29466c4284f1629d69165f37a950a41b29a6baa509ada57ca737b32a8301
BLAKE2b-256 checksum
How to use checksums
730b7f66f80039f620273339107945b60b3667b41e755c00dae9d43e16685927
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.

Transparency log

Release files / sqlclean-0.6.2-py3-none-any.whl

Download URL sqlclean-0.6.2-py3-none-any.whl
Size 29.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b4e760f4b1582aeb0ffed65e5315546eb573744453cf5d3f36284be6af5cb51a
BLAKE2b-256 checksum
How to use checksums
02ee34f81b43d41b7b92794e927e631d6e51c20253fac66cd80efd22f65de888
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.

Transparency log

Security for sqlclean 0.6.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for sqlclean-0.6.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page