Getting Started
Format one file, right now
dfmt needs to know the dialect, and nothing else:
dfmt --dialect postgres query.sql # prints the formatted file
cat query.sql | dfmt --dialect postgres - # or read stdin, write stdout
Printing is the default because it cannot hurt you. Nothing is written until you ask.
Set up a project
dfmt init records the dialect so you stop repeating it, and marks the project root:
dfmt init postgres
That writes a dlab.json:
{
"dialect": "postgres",
"include": ["**.sql"],
"exclude": []
}
Deliberately minimal. Formatting options are absent, not defaulted, so the project inherits
improvements instead of freezing today's values — and a diff of this file shows what you chose
rather than twenty settings you never thought about. dfmt init --all writes them all out if you
would rather see everything.
dlab.json marks the project root: include and exclude are relative to it, and dfmt finds
it by walking up from whatever you point it at.
Choose what to format
{
"dialect": "snowflake",
"include": ["models/**/*.sql", "macros/**/*.sql"],
"exclude": ["**/legacy/**"]
}
Set formatting options
Options live under "dfmt":
{
"dialect": "snowflake",
"dfmt": {
"keywordCase": "upper",
"maxLineWidth": 100
}
}
Every key is checked when the file loads. A name that is not an option is an error, not a shrug:
$ dfmt check .
Error: invalid "dfmt" section in dlab.json:
"keywrodCase" is not a formatter option — did you mean "keywordCase"?
The full list is in the Configuration Reference, and
dfmt tune lets you try options against your own SQL and see the result as you go.
Format
dfmt . # print
dfmt diff . # unified diff of what would change
dfmt write . # format in place
dfmt check . # exit 1 if anything needs formatting
One verb per run — there is no way to ask for two.
dbt projects
dfmt detects a dbt project by finding dbt_project.yml, and then:
- the dialect comes from the adapter in
profiles.yml(dbt-snowflake→snowflake), sodlab.jsonis optional; - models are formatted as templates —
{{ ref() }},{% if %},{% macro %}and your own macros all survive; - no
dbt compileis needed. dfmt evaluates the Jinja itself.
dfmt write . # every model
dfmt --model stg_orders # one model, by name
See dbt Integration for what happens to each kind of Jinja construct.
Format only what changed
dfmt write --changed-since main
dfmt check --changed-since HEAD~1
Override an option for one run
Any option can be a flag, and flags beat dlab.json:
dfmt write --keyword-case upper .
dfmt write --width 100 .
Shell completion
dfmt completion zsh > ~/.zsh/completions/_dfmt
dfmt completion bash > /etc/bash_completion.d/dfmt
dfmt completion fish > ~/.config/fish/completions/dfmt.fish