Run, Build and Install
go run compiles to a temporary binary and executes it, go build leaves the binary in your folder, go install puts it on your PATH.
go run . | go build [-o name] . | go install .Three commands turn source into something that runs. What separates them is what they leave behind.
go run
go run . compiles the package in the current directory, writes the executable into a temporary directory, runs it, then deletes it. Nothing appears in your folder. This is the command you use while writing code. Compiled pieces are kept in a build cache, so the second run is far quicker than the first.
go build
go build . compiles and keeps the executable in the current directory. It is named after the last part of your module path, so the module example.com/greet produces a file called greet. Use -o to choose the name or the location: go build -o bin/app .. A bare go build with nothing after it means go build . — the dot stands for the current directory, and the two forms are the same command.
go install
go install . builds the executable and moves it into your bin directory: $GOBIN when you have set it, otherwise $HOME/go/bin. With that directory on PATH you can then type the program's name from anywhere. go install example.com/cmd/tool@latest installs somebody else's program at a chosen version without changing your own project's dependencies. That form requires the @version part and has worked since Go 1.16.
Example
package main
import "fmt"
// While writing: go run .
// To keep a file: go build -o greet . then ./greet
// To install it: go install . then greet
func main() {
fmt.Println("hello from greet")
}
// Output:
// hello from greet
When to use it
- Iterate on a program during development without filling the directory with binaries.
- Produce a single file to copy onto a server or into a container image.
- Install a Go command line tool, such as a code generator, at a pinned version.
More examples
The three commands side by side
Note the ls after go run: the binary existed only in a temporary directory and is already gone. go build leaves greet next to your source, named from the module path. go install leaves nothing here at all, because the binary went to $HOME/go/bin. Add that binary name to .gitignore, since build output does not belong in version control.
$ go run .
hello from greet
$ ls
go.mod main.go
$ go build .
$ ls
go.mod greet main.go
$ ./greet
hello from greet
$ go install .
$ greet
hello from greetNaming the output and building everything
-o is how release scripts and Dockerfiles control the output path, because the default name follows the module path and is rarely what an image wants. ./... means this directory and everything under it: go build over a library package writes no file, it only proves the code compiles, which makes it a cheap first step in CI.
$ go build -o bin/api ./cmd/api # one program, written to bin/api
$ go build ./... # compile every package in the module as a check
$ go vet ./... # and check them for likely mistakesInstalling a tool at a version
The @version form, added in Go 1.16, builds the named program in isolation: your go.mod and go.sum are untouched, so installing a tool cannot change what your own project depends on. Pin an exact version such as @v0.21.0 instead of @latest when a team needs everyone to run the same tool.
$ go install golang.org/x/tools/cmd/stringer@latest
$ stringer -help
Discussion