Menu

go run vs go build vs go install: Compile and Run Go

What go run, go build and go install each do, how Go names the binary, how to cross-compile with GOOS and GOARCH, and the go fmt and go vet checks to run before you commit.

This page includes runnable editors - edit, run, and see output instantly.

go run compiles and runs a program in one step and keeps no binary. go build compiles and leaves an executable in the current directory. go install compiles and puts the executable in $HOME/go/bin. All three compile to native machine code; none of them interprets anything.

CommandCompilesRunsKeeps a binaryWhere the binary goes
go run .yesyesnotemporary directory, deleted afterwards
go buildyesnoyescurrent directory (or -o path)
go installyesnoyes$GOBIN, else $GOPATH/bin

The program below is the one used in the examples on this page. The editor runs it the way go run would.

go run

go run takes a package (usually ., the current directory) or a list of .go files:

go run .
go run main.go
go run ./cmd/server

Everything after the package is passed to your program as arguments:

go run . --port 8080 verbose
version: dev
built for: linux/amd64
args: [--port 8080 verbose]

Prefer go run . over go run main.go. Naming a file compiles only that file, so as soon as the package has a second file, functions defined there are reported as undefined. The packages and imports page covers that error in detail.

go run also runs a remote program at a specific version without installing it, which is handy for code generators:

go run golang.org/x/tools/cmd/stringer@v0.30.0 -type=Color

go build

go build compiles the package in the current directory. For a main package it writes an executable; for a library package it compiles, reports errors, and discards the result.

go mod init example.com/hello
go build
ls
go.mod  hello  main.go

The binary's name follows these rules:

You runBinary name
go build in module example.com/hellohello
go build ./cmd/serverserver
go build main.gomain (named after the first file)
go build -o bin/app .bin/app
any of the above with GOOS=windowssame name plus .exe

Two more forms you will use constantly:

go build ./...      # compile every package in the module
go vet ./...        # static checks, covered below

./... means "this directory and every directory below it". go build ./... with several main packages does not write any binaries; it is a fast "does everything compile" check.

Useful build flags

FlagWhat it does
-o nameoutput file or directory
-vprint package names as they compile
-racebuild with the data race detector (slower, larger binary; for testing)
-trimpathremove local file system paths from the binary, for reproducible builds
-ldflags "-s -w"strip the symbol table and DWARF debug info, making the binary smaller
-ldflags "-X main.version=1.4.0"set a string variable at link time
-tags nameinclude files guarded by a //go:build name constraint

The -X flag is how most Go projects stamp a version into the binary. It only works on package-level string variables (not constants):

go build -o app -ldflags "-X main.version=1.4.0" .
./app
version: 1.4.0
built for: linux/amd64
args: []

The binary also records its module versions and, since Go 1.18, the VCS commit it was built from. go version -m ./app prints them, and a program can read them with runtime/debug.ReadBuildInfo.

go install

go install builds exactly like go build and then moves the executable to $GOBIN, or $GOPATH/bin when GOBIN is unset (by default $HOME/go/bin):

go install .
go env GOPATH

Its most common use is installing tools written in Go. With @version it installs a program without touching your go.mod:

go install golang.org/x/tools/gopls@latest
go install honnef.co/go/tools/cmd/staticcheck@latest

If the shell cannot find a tool afterwards, $HOME/go/bin is not on your PATH. Add export PATH=$PATH:$(go env GOPATH)/bin to your shell profile.

Cross-Compiling with GOOS and GOARCH

Go can build for another operating system or CPU from any machine, with no extra toolchain. Set two environment variables for the build command:

GOOS=linux GOARCH=amd64 go build -o app-linux-amd64 .
GOOS=linux GOARCH=arm64 go build -o app-linux-arm64 .
GOOS=darwin GOARCH=arm64 go build -o app-macos .
GOOS=windows GOARCH=amd64 go build -o app.exe .

In PowerShell, environment variables are set differently:

$env:GOOS = "linux"; $env:GOARCH = "amd64"; go build -o app-linux .

The most common pairs:

GOOSGOARCHTarget
linuxamd64most servers and containers
linuxarm64AWS Graviton, Raspberry Pi with a 64-bit OS
darwinarm64Apple Silicon Macs
darwinamd64Intel Macs
windowsamd6464-bit Windows
jswasmWebAssembly in a browser

go tool dist list prints every supported pair (48 in Go 1.24).

Cross-compiling is this easy only for pure Go code. A package that uses cgo (C code, for example some SQLite drivers) needs a C cross-compiler for the target. When cross-compiling, cgo is disabled by default, and setting CGO_ENABLED=0 explicitly also gives you a fully static Linux binary, which is what you want in a minimal scratch or distroless container image.

go fmt and go vet

Two checks belong in every workflow, and in CI.

go fmt rewrites files in the one official style: tabs, aligned fields, normalized spacing. It is a wrapper around gofmt -l -w:

go fmt ./...
gofmt -l .     # list files that are not formatted; empty output means clean

go vet reports code that compiles but is almost certainly wrong. Printf format mismatches are the classic case:

package main

import "fmt"

func main() {
	count := 3
	fmt.Printf("%s items\n", count)
}
go vet ./...
# example.com/hello
# [example.com/hello]
./main.go:7:2: fmt.Printf format %s has arg count of wrong type int

The program compiles and prints %!s(int=3) items, which is exactly the kind of bug vet exists to catch. Other vet checks include copying a sync.Mutex by value, unreachable code, struct tags with bad syntax, and a context.CancelFunc that is never called. go test runs a subset of these checks automatically; go build runs none.

Other go Subcommands

CommandPurpose
go test ./...run tests
go mod tidyadd missing and remove unused dependencies
go get pkg@versionadd or change a dependency
go clean -cacheempty the build cache
go envprint Go's configuration
go doc fmt.Printlnshow documentation in the terminal
go list -m alllist every module in the build

Why Builds Are Fast the Second Time

Go caches compiled packages in the build cache (go env GOCACHE). A rebuild recompiles only packages whose source or dependencies changed, so go run . on an unchanged project starts almost instantly. If a build ever behaves strangely after changing Go versions or environment variables, go clean -cache clears it; you should rarely need to.

Frequently Asked Questions

What is the difference between go run and go build?

go run compiles the program into a temporary directory, runs it, and throws the binary away. go build compiles the program and writes the binary into the current directory so you can run it again or copy it elsewhere. Use go run while developing and go build when you need the executable.

How do I set the output file name of go build?

Use -o: go build -o myapp . writes myapp (on Windows, write -o myapp.exe yourself). Without -o, go build names the binary after the last element of the package's import path, or after the first file when you pass .go files, and adds .exe when building for Windows.

How do I cross-compile Go for Linux or Windows?

Set GOOS and GOARCH for the build: GOOS=linux GOARCH=amd64 go build -o app-linux . or GOOS=windows GOARCH=amd64 go build . (which produces a .exe). No extra toolchain is needed for pure Go code. go tool dist list prints every supported pair.

Where does go install put the binary?

In $GOBIN if it is set, otherwise in $GOPATH/bin, which is $HOME/go/bin by default. Add that directory to your PATH to run installed tools by name. go install example.com/tool@latest installs a tool without adding it to your module.

Does go build run go vet?

No. go build only compiles. go test runs a subset of go vet checks automatically, but for the full set run go vet ./... yourself, typically in CI next to gofmt -l ..

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED