Last Updated: May 22, 2026
Most languages require you to cobble together a compiler, a formatter, a linter, a package manager, and a test runner from different sources. Go ships all of these as subcommands of a single binary: go. This chapter walks through each tool, what it does, and how they fit together in your daily workflow.
go Command: One Tool for EverythingWhen you installed Go, you got one executable called go. Every major development task, compiling, formatting, testing, fetching dependencies, runs through it. There's no separate make, no pip, no npm. Just go followed by a verb.
Here are the subcommands you'll use most often:
| Command | Purpose |
|---|---|
go build | Compile your code into a binary |
go run | Compile and run in one step |
go fmt | Format your code |
go vet | Catch common mistakes |
go mod init | Start a new module |
go mod tidy | Clean up dependencies |
go get | Add or update a dependency |
go test | Run tests |
go doc | Read documentation from the terminal |
go install | Build and install a binary |
This diagram shows how these tools fit into a typical development cycle:
The rest of this chapter covers each tool in detail.
go build: Compiling to a Binarygo build compiles your Go source code into a standalone executable. The result is a single binary with no external dependencies, no runtime to install, nothing. You can copy it to another machine and run it.
Create a file called main.go:
Now compile it:
This produces a binary called main (or main.exe on Windows) in your current directory. Run it directly:
By default, go build names the binary after the source file or the module directory. You can choose a different name with the -o flag:
Now you have a binary called catalog instead of main. For a real project, you'd typically name the binary after your application.
One of Go's standout features is cross-compilation. You can build a binary for a different operating system or processor architecture by setting two environment variables: GOOS (target OS) and GOARCH (target architecture).
Each command produces a binary for a different platform, all from the same source code, on your current machine. No cross-compiler setup, no Docker container, no virtual machine.
Here are the most common target combinations:
| GOOS | GOARCH | Platform |
|---|---|---|
linux | amd64 | Linux (Intel/AMD 64-bit) |
linux | arm64 | Linux (ARM, e.g., AWS Graviton) |
darwin | amd64 | macOS (Intel) |
darwin | arm64 | macOS (Apple Silicon) |
windows | amd64 | Windows (64-bit) |
go run: Compile and Run in One StepDuring development, you often want to run your code without bothering about the output binary. go run compiles your program to a temporary location and executes it immediately.
go run is perfect for quick iteration. You change code, run it, see the result, and repeat. No binary file clutters your directory.
The key difference from go build: go run doesn't leave a binary behind. It compiles to a temporary file, runs it, then cleans up. Use go build when you need a binary to deploy or share. Use go run when you're developing and testing locally.
You can also pass multiple files to go run if your program spans several files in the same package:
Or use a dot to run all Go files in the current directory:
go fmt: Automatic Code FormattingGo takes an unusual stance on formatting: there's one official style, and a tool enforces it. No debates about tabs vs. spaces, brace placement, or import ordering. go fmt reformats your code to match the Go standard, and every Go developer uses it.
Say you write this code with inconsistent spacing:
Run go fmt:
The file is rewritten in place to:
Tabs for indentation, consistent spacing around operators, proper alignment. Every Go file looks the same regardless of who wrote it.
This might feel restrictive if you're used to configuring formatters with dozens of options. But the Go team made this decision deliberately. When every Go project uses identical formatting, you spend zero time discussing style in code reviews. You read any Go codebase and it looks familiar. Your editor can format on save without any configuration file. The cognitive overhead of style choices simply disappears.
Most editors run go fmt automatically when you save a file. If yours doesn't, it's worth setting that up. You'll never think about formatting again.
There's also a standalone tool called gofmt (no space). go fmt is a wrapper around gofmt that works on packages, while gofmt works on individual files with a few extra flags. For day-to-day work, go fmt is all you need.
go vet: Catching Common MistakesYour code can compile perfectly and still have bugs. go vet is a static analysis tool that catches mistakes the compiler doesn't flag, things that are syntactically valid Go but almost certainly wrong.
Here's a classic example with a format string mismatch:
This compiles fine. %d and %s are both valid format verbs. But %d expects an integer and we're passing a string, and %s expects a string and we're passing a float. The output would be garbage.
Run go vet:
go vet caught both mismatches before the program ran.
go vet Catchesgo vet checks for a range of issues:
| Check | What It Catches |
|---|---|
| Printf format strings | Format verb doesn't match argument type |
| Unreachable code | Code after return, break, or os.Exit |
| Unused results | Calling a function for its return value but ignoring it |
| Struct tag validity | Malformed or misquoted struct tags |
| Copy of locks | Accidentally copying a sync.Mutex |
| Boolean conditions | Conditions that are always true or always false |
Here's another example. This code has unreachable code after a return:
The fmt.Println after return will never execute. go vet flags it:
Get in the habit of running go vet before committing code. Many teams add it to their CI pipeline so these mistakes never reach production.
go mod init and go mod tidy: Module ManagementEvery Go project starts with a module. A module is a collection of Go packages versioned together, and it's defined by a go.mod file at the root of your project.
This creates a go.mod file:
The module path (github.com/yourname/store) is how other projects import your code. For projects you don't plan to publish, any name works, but using a URL-style path is the Go convention.
go mod tidyAs you add imports and remove them, your go.mod and go.sum files can get out of sync. go mod tidy fixes that. It adds any missing dependencies and removes ones you're no longer using.
Run this after adding or removing imports. It's safe to run at any time, and it won't change anything if your dependencies are already clean.
go get: Adding DependenciesWhen your code needs an external package, go get downloads it and adds it to your go.mod file.
After running this, you can import and use the package in your code:
(The actual UUID will be different each time you run it.)
You can also request a specific version:
And to update a dependency to its latest version:
go test: A Brief IntroductionGo has a built-in testing framework. No external libraries to install, no configuration files to write. You put test functions in files ending with _test.go, and go test runs them.
Here's a quick taste. Given a function that calculates a discounted price:
You'd write a test in pricing_test.go:
Run it:
go test will be covered in depth, including table-driven tests, subtests, benchmarks, and code coverage. For now, just know it exists and it's built in.
go doc: Reading Documentation from the Terminalgo doc shows documentation for any package, type, or function right in your terminal. No browser needed.
You can browse an entire package:
Or look up a specific type:
This is faster than switching to a browser, and the documentation comes directly from the source code comments. In Go, documentation is part of the code, not a separate system. Any comment placed directly above a function, type, or package declaration becomes its documentation.
go install: Installing Binariesgo install builds a binary and places it in your $GOPATH/bin directory (or $HOME/go/bin by default). This is how you install Go tools that you want available as commands on your system.
For your own project:
This compiles the current module and puts the binary in your Go bin directory.
For installing third-party tools:
After running this, goimports is available as a command in your terminal (assuming $GOPATH/bin is in your PATH). Many Go developers use goimports as an enhanced version of go fmt that also manages import statements automatically.
The difference between go build and go install: go build puts the binary in your current directory (or wherever -o points). go install puts it in $GOPATH/bin so it's accessible from anywhere.
Here's what a typical workflow looks like when starting a new project. Let's say you're building a small order processing tool.
Step 1: Initialize the module.
Step 2: Write your code.
Create main.go:
Step 3: Format the code.
The ./... pattern means "this directory and all subdirectories." It's a Go convention for running tools across your entire project.
Step 4: Check for mistakes.
Step 5: Run it.
Step 6: Build the final binary.
This diagram summarizes the flow from new project to deployed binary: