Skip to main content

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-snowflakesnowflake), so dlab.json is optional;
  • models are formatted as templates{{ ref() }}, {% if %}, {% macro %} and your own macros all survive;
  • no dbt compile is 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