Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

ModeCommandExit behavior
Printsql-dialect-fmt query.sqlformatted SQL on stdout
Writesql-dialect-fmt --write query.sqlrewrites files in place
Checksql-dialect-fmt --check sql/exits 1 if any file would change
Diffsql-dialect-fmt --check --diff sql/prints unified diffs for unformatted files

Options

OptionMeaning
--dialect snowflake|databricksSelect SQL dialect.
--line-width NTarget print width.
--indent-width NSpaces per indent level.
--no-uppercasePreserve keyword casing instead of upper-casing keywords.
--stdin-filepath PATHUse a path for stdin config discovery and diagnostics.
--no-configIgnore sql-dialect-fmt.toml.
--writeRewrite path arguments in place.
--checkVerify formatting without writing.
--diffShow 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, and ORDER BY start 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.