cmd / pgfmt
pgfmt is a SQL formatter for Postgres query files.
For the query layout, see
go / postgres. For a static check
over the same files, see cmd / nullscan.
I run it on */queries/*.sql so reviews do not spend time on style.
Install
pgfmt lives in its own module. Add it to a project as a module tool:
go get -tool github.com/croaky/pgfmt/cmd/pgfmt
That writes a tool line to go.mod next to the require line that
pins the version:
tool github.com/croaky/pgfmt/cmd/pgfmt
Why go tool
Go 1.24 added the tool directive. go tool <name> builds and runs the
pinned version from the module cache. Local commands and CI use the same
version from go.mod. Several repos share one implementation.
There is no install step and nothing to put on $PATH. A tool upgrade
appears in git history.
Go caches the binary after the first build.
Command
Format in place:
go tool pgfmt -w <pkg>/queries/*.sql
Format a named file to stdout:
go tool pgfmt query.sql
Format stdin to stdout:
cat query.sql | go tool pgfmt
CI
The -c flag checks formatting, exits with an error if a file needs
changes, and writes nothing. It prints the command to fix each file:
FAIL: <path> needs formatting. Run: pgfmt -w <path>
-c and -w are mutually exclusive.
In a cibot Checkfile, that is one line:
sqlfmt: git ls-files -z '*queries/*.sql' | xargs -0 go tool pgfmt -c
Style
- Uppercase SQL keywords. Type names (
bigint,text,interval) stay lowercase. - Lowercase function names.
- Two-space indentation.
- An 80-column limit decides when a line wraps.
- Vertical clause lists (
SELECT,FROM,WHERE,ORDER BY). - Stable wrapping for
CASE,NOT EXISTS, and joins. - Paired-argument functions (
jsonb_build_object) wrap two arguments per line.
DDL keywords such as index, key, and add become uppercase only
inside CREATE, ALTER, and DROP. In DML they are often column
names, so they stay lowercase.
pgfmt is idempotent.
Safety
After formatting, pgfmt parses its output and compares the token
stream to the input. If they differ, it fails and writes nothing.
Comments are the one exception. pgfmt keeps standalone comments on
their own line, but drops trailing comments and comments inside
parentheses.
Workflow
- Write or edit SQL in
<pkg>/queries/*.sql. - Run
go tool pgfmt -w <pkg>/queries/*.sql. - Commit the formatted SQL with the Go call-site changes.