Home / Alt manpages / gofmt(1)

  • gofmt(1)
  • User command
  • linux

Format Go Code Safely with gofmt

You will finish with a small, repeatable workflow for checking and formatting Go source with the installed gofmt 1.22. The workflow starts with a diff, keeps a backup before an overwrite, and separates formatting from optional source rewrites.

Allow about ten minutes for a first pass. You need a shell, a readable Go source tree and the gofmt command from the Debian golang-go package. No step needs elevated privileges. Do not use sudo to format code in a project you do not own: root can create root-owned files and hide an ordinary permission problem.

1. Confirm the installed formatter

Check the command and package version before relying on its exact behaviour. This is read-only:

$ command -v gofmt
/home/linuxbrew/.linuxbrew/bin/gofmt
$ gofmt -h | sed -n '1,12p'
usage: gofmt [flags] [path ...]
  -cpuprofile string
        write cpu profile to this file
  -d    display diffs instead of rewriting files
  -e    report all errors (not just the first 10 on different lines)
  -l    list files whose formatting differs
  -r string
        rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')
  -s    simplify code
  -w    write result to (source) file instead of stdout
$ dpkg-query -W -f='${Package} ${Version}\n' golang-go:amd64
golang-go:amd64 2:1.22~2build1

The path printed by command -v is the binary you are actually invoking. The Debian package version identifies the installed distribution package, while the command itself does not provide a --version flag in this installation. Keep that distinction in mind when comparing output between machines.

Checkpoint

You have confirmed the executable and recorded the local package version.

2. Inspect a file without changing it

By default, gofmt writes the reformatted source to standard output. That makes this a safe first check, but redirecting it casually can still overwrite a file. Start with a diff instead. Create a disposable example if you do not already have a Go file to inspect:

$ tmpdir=$(mktemp -d)
$ printf '%s\n' 'package main' '' 'import "fmt"' '' 'func main(){fmt.Println("hello")}' > "$tmpdir/main.go"
$ gofmt -d "$tmpdir/main.go"
diff "$tmpdir/main.go" gofmt/main.go
--- gofmt/main.go
+++ gofmt/main.go
@@
-func main(){fmt.Println("hello")}
+func main() { fmt.Println("hello") }

The exact diff header includes a temporary path and gofmt's output uses tabs for indentation, which may display as spacing in a terminal. The important result is that the file is still unchanged. Remove the disposable directory after the experiment with rm -rf "$tmpdir"; it contains only the file you just created.

For a real project, replace the temporary path with a known file:

$ gofmt -d -- ./path/to/file.go

The -- marks the end of options. It is useful when a path is supplied by a script, although a path beginning with a hyphen is best rejected rather than guessed at.

3. Check a tree without rewriting it

Use -l in a pre-commit check or before reviewing a branch. It prints the names of files whose formatting differs and prints nothing when they are already formatted:

$ gofmt -l -- ./path/to/package
./path/to/package/main.go
./path/to/package/worker.go
$ gofmt -l -- ./path/to/package | tee /tmp/gofmt-files.txt
$ test ! -s /tmp/gofmt-files.txt && echo 'all Go files are formatted'
all Go files are formatted

A directory is searched recursively for .go files, but files whose names start with a period are ignored. The command does not understand your build graph, run tests or prove that the program is correct. It only reports formatting differences.

Checkpoint

Use -l when you need a yes-or-no check, and -d when you need to review the actual edits.

4. Apply ordinary formatting after reviewing the diff

Once the diff is expected, use -w to update the source file in place:

$ cp --preserve=all ./path/to/file.go ./path/to/file.go.bak
$ gofmt -w -- ./path/to/file.go
$ gofmt -d -- ./path/to/file.go
$ test ! -s <(gofmt -l -- ./path/to/file.go) && echo 'file is formatted'
file is formatted

The backup is an explicit recovery point. If the result is wrong for your workflow, restore it with cp --preserve=all ./path/to/file.go.bak ./path/to/file.go. Do not remove the backup until you have reviewed the complete change and, ideally, run the project's tests. Deleting it with rm is irreversible.

-w normally restores the original file if an error occurs while overwriting, but it is still wise to keep your own backup when a change matters. Formatting can alter whitespace throughout a file, so inspect the diff rather than assuming a successful exit means a small diff.

5. Format standard input and fragments

With no path, gofmt reads standard input and prints formatted text. This is useful in a pipeline and does not modify a source file:

$ printf '%s\n' 'func main(){println("hello")}' | gofmt
func main() {
        println("hello")
}

Standard input can be a full Go program or a syntactically valid declaration list, statement list or expression. For example:

$ printf '%s\n' 'x:=1+2' | gofmt
x := 1 + 2

Leading indentation and leading or trailing spaces have special preservation rules for fragments. If a pipeline's output is going back into a larger file, verify the surrounding context rather than treating the fragment as a complete program.

6. Use simplification and rewrites deliberately

The -s option asks gofmt to simplify code after applying any rewrite rule. In the installed tool, that includes forms such as s[a:len(s)] becoming s[a:], and a loop that discards both range values becoming for range v. The manual warns that simplification can produce code incompatible with earlier Go versions, so review and test the resulting diff:

$ gofmt -s -d -- ./path/to/file.go
$ gofmt -s -w -- ./path/to/file.go

The -r option applies a rule in the form pattern -> replacement. Lowercase single-character identifiers in the pattern act as wildcards:

$ gofmt -r '(a) -> a' -l -- ./path/to/package
$ gofmt -r '(a) -> a' -w -- ./path/to/package

Do not combine an unreviewed rewrite with a broad tree and an automatic commit. First run it with -l or -d on a small, known set, then test the result. A rewrite is a source change, not merely presentation.

7. Diagnose failures without guessing

For malformed input, use -e when you need all available errors rather than the first ten reported on different lines:

$ gofmt -e -- ./path/to/file.go
$ printf 'exit status: %s\n' "$?"
exit status: 0

Replace the example path with the file that failed. A non-zero status means gofmt could not complete its requested operation. Check the path, read permission and source syntax first:

$ test -r ./path/to/file.go && echo readable
$ gofmt -d -- ./path/to/file.go

Do not fix an access problem by running as root unless the project owner and ownership change are understood. If a generated file is repeatedly reported, find the generator or build step that writes it; formatting the generated output may only hide the real source of the difference.

Done means

  • You confirmed the installed gofmt binary and Debian package version.
  • You used -d or -l before changing source.
  • You reviewed the diff before using -w.
  • You kept a recoverable backup for an in-place change.
  • You treated -s and -r as source transformations that need testing.
  • The final gofmt -l check reports no files needing formatting.