Go already includes most of the tools needed for a dependable development loop. This guide shows how to order them so formatting, tests, static analysis, documentation, and builds provide fast feedback before code reaches review.
The examples support Go 1.22 and later. The test below was executed with Go 1.24.7 on Windows amd64.
Match each Go tool to a feedback question
Tools are useful when each answers a specific question. gofmt asks whether source has canonical formatting. go test asks whether observed behavior matches your assertions. go vet reports suspicious constructs that compile but are likely mistakes. go build asks whether packages and commands compile into an artifact.
The official command documentation is the source of truth for flags and behavior. The broader Go tutorial explains the language concepts those commands operate on.
Run the cheapest checks first:
- Format changed files with
gofmt. - Run focused package tests while editing.
- Run
go test ./...across the module. - Run
go vet ./...for suspicious code. - Build the command you intend to ship.
This order shortens the time between a mistake and its explanation. A formatting failure should not wait behind a complete integration suite.
Verify a small package with go test
The package function validates its input rather than silently accepting an empty slice. That makes the failure contract visible to callers and testable.
package calc
import "errors"
func Sum(values []int) (int, error) {
if len(values) == 0 {
return 0, errors.New("sum values: input is empty")
}
total := 0
for _, value := range values {
total += value
}
return total, nil
}
The test handles the returned error before checking the result.
package calc
import "testing"
func TestSum(t *testing.T) {
total, err := Sum([]int{2, 3, 5})
if err != nil {
t.Fatalf("Sum returned an error: %v", err)
}
if total != 10 {
t.Fatalf("Sum = %d, want 10", total)
}
}
Run go test -v in the package directory.
Output:
=== RUN TestSum
--- PASS: TestSum (0.00s)
PASS
ok example.com/tools 0.606s
Both code blocks were tested together. Elapsed time varies by machine and is not a performance benchmark.
Build a stepwise pre-review workflow
Start with a module described in Golang file structure. During a change, run go test in the package you are touching. The narrow scope keeps the edit-feedback cycle short.
Before committing, format and test the module:
gofmt -w .
go test ./...
go vet ./...
Review formatting changes before staging them. gofmt -w . writes files below the current directory, so run it from the intended module root.
When a repository contains concurrent code, add go test -race ./... on supported platforms. The race detector adds time and memory overhead, which makes it better suited to a deliberate check than every keystroke. For performance-sensitive functions, add benchmarks and compare multiple runs rather than treating one result as proof.
Next, build the real entry point. A repository with cmd/server can use:
go build ./cmd/server
Read Go compilation and execution for the difference between running packages, producing a binary, and installing a command.
Finally, make CI repeat the repository-wide commands on every proposed change. Local tools optimize feedback speed; CI provides a clean environment and shared gate. They solve related but different problems.
Use inspection commands before guessing
go doc shows documentation for packages and symbols without leaving the terminal. go list exposes package and module metadata for scripts. go env explains which toolchain settings are active. go mod tidy synchronizes module requirements with imported packages, but its diff should be reviewed because it changes go.mod and go.sum.
Use go version and go env GOMOD when a command behaves differently from expectations. These two checks often reveal that the wrong toolchain is active or that the command is outside the intended module.
Common mistakes
Treating gofmt as a style preference
Manually aligning code creates noisy review discussions and inconsistent files. Run gofmt and accept its canonical output.
Running only the current package before merging
A package can pass while a dependent package fails to compile. Keep focused tests during editing, then run go test ./... from the module root before review.
Using go vet as a replacement for tests
go vet finds selected suspicious constructs; it does not know the product behavior you intended. Keep behavioral assertions in tests and use vet as another signal.
What next
Apply the workflow to a small module using the Go study guide, then organize it with the file structure guide. When it is ready to distribute, use the compilation and execution guide to produce the correct artifact.