Editors
dfmt formats the buffer you are editing, not the file on disk, and it formats a dbt model as that
model: with its config, its refs and the project's macros. Editors reach it through the language
server, dfmt lsp. It stays running for the editor window, so a dbt project is loaded once instead
of on every save, and it reads the same dlab.json every dfmt command reads: set the project up
once with dfmt setup, and the editor formats exactly as dfmt write does.
VS Code, Cursor, Windsurf
In the Extensions view, search for Datoria and install the extension called dlab, by
Datoria. It is in both the Visual Studio Marketplace and Open VSX. It formats .sql files whatever
language mode they are in, so it works beside dbt Power User and Better Jinja, and it registers for
their jinja-sql mode too.
The first time it opens a workspace containing a dbt project, it offers to become the default
formatter for SQL and dbt models and to format on save. To do the same by hand, put this in
.vscode/settings.json:
{
"[sql]": {
"editor.defaultFormatter": "datoria.dlab",
"editor.formatOnSave": true
},
"[jinja-sql]": {
"editor.defaultFormatter": "datoria.dlab",
"editor.formatOnSave": true
}
}
The default formatter setting matters: with two formatters registered for a language and no default, VS Code asks you to choose and formats with neither until you do.
You do not need to install dfmt first. The extension starts the language server from the dfmt
you installed when it finds it on your PATH. When there is none, it downloads the
release for your platform itself, into ~/Library/Caches/dlab on macOS, ~/.cache/dlab on Linux
or %LOCALAPPDATA%\dlab on Windows. A "version" in your project's dlab.json, or the
dlab.version setting, pins which release it downloads. The dlab.path setting points it at a
specific binary instead.
What you see. Warnings dfmt reports about the file appear in the Problems panel at the line
they concern. The status bar shows the last result. When dfmt declines to format a file, the buffer
is left exactly as it was and the reason is in the Problems panel and the extension's output
channel. A file outside any dbt project or dlab.json has no dialect: run dfmt setup in the
project.
The options pane. Run dlab: Open the formatting options pane with an SQL file open. A panel
opens beside the editor with one control per formatting option, plus the dialect. Every change is
written to the project's dlab.json and the open file is reformatted at once, so you can keep the
pane open and try things. Options left at their default are not written, the same rule
dfmt setup follows. The pane shows whatever dfmt options --json reports, so it always matches
the binary in use. The ruler at the line width follows maxLineWidth as you change it.
Neovim
Neovim 0.11 and later start the language server with no plugin:
vim.lsp.config("dfmt", {
cmd = { "dfmt", "lsp" },
filetypes = { "sql" },
root_markers = { "dlab.json", "dbt_project.yml", ".git" },
})
vim.lsp.enable("dfmt")
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*.sql",
callback = function(args)
vim.lsp.buf.format({ bufnr = args.buf, name = "dfmt" })
end,
})
Emacs
With eglot, built into Emacs 29 and later:
(with-eval-after-load 'eglot
(add-to-list 'eglot-server-programs '(sql-mode . ("dfmt" "lsp"))))
(add-hook 'sql-mode-hook #'eglot-ensure)
(add-hook 'sql-mode-hook
(lambda () (add-hook 'before-save-hook #'eglot-format-buffer nil t)))
JetBrains IDEs
Settings → Tools → File Watchers → add a watcher for SQL files with program dfmt, arguments
write $FilePath$, and "Trigger the watcher on external changes" off. This formats the saved file
rather than the buffer, which is the only hook those IDEs offer without a plugin.
Any other editor
Point the editor's language-server client at dfmt lsp, which speaks the Language Server Protocol
over stdin and stdout. It answers whole-document formatting requests and reports dfmt's warnings
as diagnostics. When dfmt declines to format a file, the answer is no edits, and the reason is a
diagnostic.