Skip to content

The Go Toolchain

The go binary ships every tool a Go developer needs in a single executable. There is no separate build system, no Makefile required for basic workflows, and no plugin ecosystem to configure. The following commands cover 90% of daily Go development.

go run — compile and execute in one step

Section titled “go run — compile and execute in one step”

go run compiles the specified files and runs the resulting binary immediately. It is perfect for scripts and quick experiments — no output file is left on disk.

Terminal window
go run main.go
go run . # run the package in the current directory
go run ./cmd/server # run a specific cmd sub-package

go build compiles the package and writes the binary to disk. Without a -o flag the binary is named after the module in the current directory.

Terminal window
go build . # build current package, output: ./myapp
go build -o bin/server ./cmd/server # build to a specific path
# Cross-compile for Linux/amd64 from macOS
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o bin/server ./cmd/server

The -ldflags="-s -w" flags strip the symbol table and DWARF debug info, reducing binary size significantly. CGO_ENABLED=0 guarantees a fully static binary — no dynamic libc dependency.

go fmt runs gofmt on all .go files in a package and writes the result back to disk. There is exactly one way to format Go code.

Terminal window
go fmt ./... # format every package in the module
gofmt -w -l ./ # equivalent: write changes, list modified files

In CI, check that code is already formatted:

Terminal window
gofmt -l . | grep -q . && echo "unformatted files found" && exit 1 || echo "all formatted"

go vet runs a suite of static analysers that catch bugs the compiler does not catch: mismatched Printf format verbs, unreachable code, incorrect mutex usage, and more.

Terminal window
go vet ./...

Sample issues go vet catches:

fmt.Printf("%d", "hello") // vet: format %d has arg "hello" of wrong type string
var mu sync.Mutex
mu2 := mu // vet: assignment copies lock value

go vet exits with a non-zero status if it finds problems, making it easy to fail a CI pipeline.

go doc prints the documentation for any package, type, function, or method — without leaving the terminal.

Terminal window
go doc fmt # package overview
go doc fmt.Println # specific function
go doc net/http.Request # type in a sub-package
go doc -all net/http # every exported symbol in the package

For a richer browser-based experience, use pkgsite (the Go package documentation server) or browse pkg.go.dev.

Putting it together — a typical CI pipeline

Section titled “Putting it together — a typical CI pipeline”
Terminal window
go fmt ./... && \
go vet ./... && \
go test -race -coverprofile=coverage.out -covermode=atomic ./... && \
go build ./...

This four-command pipeline catches formatting drift, static bugs, data races, and compilation errors before code is merged.

What is the difference between go run and go build?
Which flags should you combine with go build when cross-compiling a static Linux binary?
What kind of issues does go vet detect that the compiler does not?
Which command shows documentation for fmt.Println in the terminal?