sql-dialect-fmt
sql-dialect-fmt is an opinionated Rust formatter and editor toolchain for Snowflake SQL and
Databricks SQL. It is built around a lossless lexer/parser pipeline: unsupported or malformed input
is preserved, comments survive formatting, and repeated formatting is stable.
Use the playground to run the WebAssembly formatter in the browser, or install the CLI for local and CI usage.
cargo install sql-dialect-fmt --version 1.18.0 --locked
sql-dialect-fmt --check sql/**/*.sql
sql-dialect-fmt --write sql/**/*.sql
Coverage
- Snowflake SELECT, DML, COPY, major DDL and object DDL.
- Snowflake Scripting and routine bodies in SQL, JavaScript, Python, Java, and Scala.
- Databricks mode for backtick identifiers, LATERAL VIEW, Delta DDL options, time travel, higher-order function lambdas, and SQL scripting blocks.
- LSP, semantic tokens, hover text, Tree-sitter grammar, VS Code packaging, and Chrome/WASM extension packaging.
The detailed tracker lives in spec/seed/features.json; run:
python3 spec/snowflake_spec.py coverage
Playground
The formatter runs locally in the browser through sql-dialect-fmt-wasm; SQL text is not sent to a
server.
CLI Reference
sql-dialect-fmt [OPTIONS] [PATH ...]
With no paths, or with -, the CLI reads stdin and writes formatted SQL to stdout. Directory
arguments are searched recursively for *.sql files while common generated directories such as
.git, node_modules, and target are skipped.
Modes
| Mode | Command | Exit behavior |
|---|---|---|
sql-dialect-fmt query.sql | formatted SQL on stdout | |
| Write | sql-dialect-fmt --write query.sql | rewrites files in place |
| Check | sql-dialect-fmt --check sql/ | exits 1 if any file would change |
| Diff | sql-dialect-fmt --check --diff sql/ | prints unified diffs for unformatted files |
Options
| Option | Meaning |
|---|---|
--dialect snowflake|databricks | Select SQL dialect. |
--line-width N | Target print width. |
--indent-width N | Spaces per indent level. |
--no-uppercase | Preserve keyword casing instead of upper-casing keywords. |
--stdin-filepath PATH | Use a path for stdin config discovery and diagnostics. |
--no-config | Ignore sql-dialect-fmt.toml. |
--write | Rewrite path arguments in place. |
--check | Verify formatting without writing. |
--diff | Show diffs with --check. |
Homebrew
brew tap hjosugi/sql-dialect-fmt https://github.com/hjosugi/sql-dialect-fmt
brew install sql-dialect-fmt
CI
- uses: hjosugi/sql-dialect-fmt@v1
with:
args: "sql/**/*.sql"
docker run --rm -v "$PWD:/work" -w /work ghcr.io/hjosugi/sql-dialect-fmt:1.18.0 --check .
pre-commit
repos:
- repo: https://github.com/hjosugi/sql-dialect-fmt
rev: v1.18.0
hooks:
- id: sql-dialect-fmt
Use sql-dialect-fmt-check for verification-only hooks.
Formatting Style
The formatter is intentionally small on options. The expected shape is stable output that can run in CI without team-local style debates.
Statements
- SQL keywords are upper-cased by default.
- Statements end with semicolons.
- Major clauses such as
SELECT,FROM,WHERE,GROUP BY,QUALIFY, andORDER BYstart on their own lines when the query is multi-line. - Comma-separated lists use one item per line when they do not fit within the configured width.
SELECT
customer_id,
COUNT(*) AS orders,
SUM(total_amount) AS revenue
FROM analytics.orders
WHERE order_status = 'paid'
GROUP BY customer_id;
Losslessness
Formatting must preserve the meaningful token stream. Inputs with lexer or parser errors are returned unchanged rather than reformatted through an uncertain tree.
Comments are preserved as leading, trailing, or dangling comments according to their CST position. Routine bodies and embedded language blocks are kept inside their original SQL delimiters.
Width And Indentation
line_width controls when groups break. indent_width controls the spaces added for nested
structures. Both options are available through the CLI, config files, the browser extension, and the
WASM playground.
Development
The workspace is split into small crates so parser, formatter, editor, and distribution changes can be tested at the layer that owns the behavior.
source bytes
-> sql-dialect-fmt-encoding
-> sql-dialect-fmt-lexer
-> sql-dialect-fmt-parser
-> sql-dialect-fmt-formatter
Standard Gates
cargo fmt --all --check
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps
cargo bench -p sql-dialect-fmt-formatter --bench format -- --test
Fuzzing
cargo install cargo-fuzz --locked
cargo +nightly fuzz run lexer_roundtrip
cargo +nightly fuzz run parser_lossless
cargo +nightly fuzz run formatter_idempotent
The scheduled fuzz workflow runs the same targets and uploads crash artifacts.
Corpus
The committed formatter corpus lives in
crates/sql-dialect-fmt-formatter/tests/corpus_sample/. Larger private or generated corpora should
use the external harness:
scripts/run-external-corpus.sh --path /path/to/sqls --limit 500
scripts/conformance-report.py --path crates/sql-dialect-fmt-formatter/tests/corpus_sample \
--out target/conformance-report.md
See also docs/ARCHITECTURE.md, docs/TESTING.md, and docs/CORPUS.md in the repository.
Release And Distribution
The project uses one workspace version in the root Cargo.toml. Published crates inherit that
version and internal dependency versions are centralized in [workspace.dependencies].
Release Gate
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps
cargo bench -p sql-dialect-fmt-formatter --bench format -- --test
cargo fmt --all --check
scripts/run-external-corpus.sh --sample
scripts/conformance-report.py --path crates/sql-dialect-fmt-formatter/tests/corpus_sample \
--out target/conformance-report.md
Assets
scripts/package-extensions.sh builds the Chrome extension zip and VS Code VSIX under
target/dist/. Version tags create the GitHub Release, publish release binaries, and push the GHCR
image. Store publishing remains gated by repository variables and secrets documented in
docs/STORE_PUBLISHING.md.
Docs Site
scripts/build-docs-site.sh
The docs workflow builds this mdBook, copies the WebAssembly formatter into the site output, and
deploys GitHub Pages from main.