a sql linter that lints like rust, ships like a binary.
drift parses postgres, mysql, sqlite, bigquery,
and ansi. 70 rules across 7 categories. about 50 to 200x faster than sqlfluff on the same corpus.
single 2.9mb binary, zero runtime deps.
$ cat reports.sql select * from users u join orders o on u.id=o.user_id where lower(u.email) like '%@oldcorp.com' order by u.id desc; update orders set status='cancelled' where amount<0; // 3 lines · 3 statements · waiting for drift
$ drift check reports.sql reports.sql:1:1 warning [drift.performance.select-star] reports.sql:1:22 warning [drift.style.keyword-case] reports.sql:2:2 info [drift.performance.fn-on-column] reports.sql:2:31 warning [drift.performance.like-leading-wildcard] reports.sql:3:1 error [drift.correctness.missing-where-guard] ──────────────────────────────────────────── 5 issues · 1 error · 4 warnings 270ms
$ drift fix reports.sql fixed reports.sql (3 safe rewrites applied, 2 left for you) SELECT * FROM users u JOIN orders o ON u.id=o.user_id WHERE LOWER(u.email) LIKE '%@oldcorp.com' ORDER BY u.id DESC; UPDATE orders SET status='cancelled' WHERE amount<0; // keyword-case · normalized // select-star · still yours. not safe to auto-rewrite // missing-where-guard · still yours. will not guess intent
$ drift rules | head -20 style 20 rules · keyword case, indent, comma style, alias quoting correctness 15 rules · missing where, cartesian join, null compare performance 8 rules · select *, like wildcards, fn on indexed column security 6 rules · plaintext passwords, grant all, superuser ddl portability 8 rules · dialect-specific syntax, non-standard casts conventions 8 rules · snake_case columns, singular table names ambiguity 5 rules · unqualified columns, duplicate aliases 70 rules total. each one has a doc page and a 'why'. run `drift explain <rule-id>` for the full writeup.
$ drift lsp & [lsp] listening on stdio [lsp] workspace root: ~/src/reports [lsp] loaded drift.toml (dialect = postgres) → helix · neovim · vscode · zed → real-time diagnostics on save + on type → quick-fixes wired through code actions → all 70 rules available in the editor // not a wrapper. speaks lsp 3.17 over stdio.
$ drift --version drift 0.14.43 (2.9mb, stripped, static) # dialects ready postgres 95% coverage · primary target mysql 80% coverage sqlite 80% coverage bigquery 60% coverage · window fns landing next ansi -- baseline fallback rust 1.75+ · mit · github.com/f4rkh4d/drift
drop a drift.toml next to your schema, run drift check, get violations
ranked by category. drift fix applies safe rewrites and refuses the unsafe ones.
drift lsp plugs into any editor that speaks lsp. 70 rules, 5 dialects, one binary.
real parser
built on sqlparser-rs with dialect-specific adapters per engine. drift reads an ast,
not a regex guess. means it can see scope, type, alias. means rules can actually reason.
five dialects
postgres is the primary and deepest. mysql, sqlite,
bigquery behind it. ansi as fallback. drift auto-detects from file extension or from
[dialect] in the toml.
seventy rules
split across style, correctness, performance, security, portability, conventions, ambiguity.
each rule has a doc page. drift explain rule-id prints the why, a good example, and a bad one.
fix that respects you
safe, deterministic rewrites only. drift will normalize keyword case all day. it will not
invent a where clause, because it does not know your intent. every fix is idempotent.
editor lsp, not a stub
real lsp 3.17 over stdio. diagnostics on save and on type, code actions for the quick-fixable rules. helix, neovim, vscode, zed picked it up with no glue. jetbrains is next, probably.
single 2.9mb binary
stripped, statically linked, zero runtime deps. cargo install --git or grab the
install script. idles at ~4mb of ram. fits in your ci image without a second thought.
seven categories, one example each
the rule ids are stable. the fixes are not always automatic. drift tells you which is which.
style keyword-case // mixed SELECT/select in one file correctness missing-where-guard // unguarded update or delete performance like-leading-wildcard // '%foo' defeats the index security plaintext-password-column // column named 'password' as text portability non-standard-cast // ::text works in pg only conventions table-name-plural // prefer 'user' over 'users' (configurable) ambiguity unqualified-column // 'id' when two tables have one
conventions is opinionated on purpose and every rule in it ships off by default.
you opt in per repo. the rest are on with sensible severity. tweak anything in drift.toml.
drift vs the sql linters you already know
feature drift sqlfluff sqlfmt pgformatter ─────────────────────── ────── ──────── ──────── ─────────── multi-dialect 5 7+ dbt only postgres speed (10k stmts) ~270ms ~45s ~2s ~6s single binary yes no (pip) no (pip) yes (perl) editor lsp yes via ext no no fix mode yes yes format-only format-only config toml dotfiles toml cli flags memory (idle) ~4 MB ~120 MB ~80 MB ~1 MB
sqlfluff has the biggest rule catalog and the deepest jinja / dbt story. drift wins on speed, distribution, and editor ux. both tools are fine. pick the one that fits your stack.
install
curl -fsSL https://drift.frkhd.com/install.sh | sh
detects os + arch, drops the binary on your PATH. set DRIFT_INSTALL_DIR if you want a specific spot.
brew install f4rkh4d/tap/drift
macos + linuxbrew. formula pinned to the latest release. tap lands with the first tagged build.
cargo install --git https://github.com/f4rkh4d/drift
rust 1.75+. grabs latest main. works right now if you want to try the bleeding edge.
mac (apple silicon + intel) and linux (amd64 + arm64). binaries on the github releases page. windows is on the list but not here yet.