dfmt
A SQL formatter that parses your SQL properly — full grammar, full AST, per dialect — and formats dbt models without pretending Jinja is a comment.
dfmt init postgres # record the dialect
dfmt diff . # see what would change
dfmt write . # format
dfmt check . # exit 1 if anything is unformatted
What makes it different
It knows the dialect. dfmt shares its parser with Datoria's lineage and type-inference tools:
one grammar per dialect, generated into a real parser, not a token-level pattern matcher. QUALIFY
in Snowflake, pipe syntax in BigQuery, SETTINGS in ClickHouse — these are grammar, so they format
like grammar rather than like unfamiliar text to be left alone.
It handles Jinja for real. A dbt model is a template that becomes SQL. dfmt evaluates the
template, formats the resulting SQL, and puts every {{ ref() }} and {% if %} back where it
belongs. No regexes, no "format the compiled output and hand it back", no {# fmt: off #} around
anything with a tag in it.
It refuses to guess. dfmt will not pick a dialect for you, and it will not format a template as if it were SQL. Both are the same mistake: a recovering parser accepts almost anything, so a wrong guess does not fail — it silently produces something that reads fine and means something else. When dfmt cannot tell, it says so and leaves the file alone.
It does not lose your SQL. Every run verifies that the output holds the same tokens in the same order as the input. Formatting moves whitespace; it does not edit your query.
Where to go next
- Getting Started — install, configure, format.
- CLI Reference — every flag, mode, and exit code.
- Configuration Reference — every
dlab.jsonoption, generated from the source. - dbt Integration — models, macros, and what dfmt does with Jinja.
- CI Integration —
dfmt checkin a pipeline. - Features — one page per formatting decision, each with examples that are themselves tests.