go run compila e executa um programa em um passo só e não guarda binário. go build compila e deixa um executável no diretório atual. go install compila e coloca o executável em $HOME/go/bin. Os três compilam para código de máquina nativo; nenhum deles interpreta nada.
| Comando | Compila | Executa | Guarda um binário | Para onde vai o binário |
|---|---|---|---|---|
go run . | sim | sim | não | diretório temporário, apagado depois |
go build | sim | não | sim | diretório atual (ou -o caminho) |
go install | sim | não | sim | $GOBIN, senão $GOPATH/bin |
O programa abaixo é o usado nos exemplos desta página. O editor o executa como o go run faria.
go run
go run recebe um pacote (normalmente ., o diretório atual) ou uma lista de arquivos .go:
go run .
go run main.go
go run ./cmd/server
Tudo o que vem depois do pacote é repassado ao seu programa como argumentos:
go run . --port 8080 verbose
version: dev
built for: linux/amd64
args: [--port 8080 verbose]
Prefira go run . a go run main.go. Apontar um arquivo compila só esse arquivo, então assim que o pacote ganha um segundo arquivo, as funções definidas nele aparecem como undefined. A página de pacotes e imports explica esse erro em detalhes.
O go run também executa um programa remoto em uma versão específica sem instalá-lo, o que é útil para geradores de código:
go run golang.org/x/tools/cmd/stringer@v0.30.0 -type=Color
go build
go build compila o pacote do diretório atual. Para um pacote main ele grava um executável; para um pacote de biblioteca ele compila, reporta os erros e descarta o resultado.
go mod init example.com/hello
go build
ls
go.mod hello main.go
O nome do binário segue estas regras:
| Você executa | Nome do binário |
|---|---|
go build no módulo example.com/hello | hello |
go build ./cmd/server | server |
go build main.go | main (nome do primeiro arquivo) |
go build -o bin/app . | bin/app |
qualquer um dos anteriores com GOOS=windows | o mesmo nome mais .exe |
Mais duas formas que você vai usar o tempo todo:
go build ./... # compile every package in the module
go vet ./... # static checks, covered below
./... significa "este diretório e todos os diretórios abaixo dele". go build ./... com vários pacotes main não grava binário nenhum; é uma verificação rápida de "tudo compila?".
Flags de build úteis
| Flag | O que faz |
|---|---|
-o nome | arquivo ou diretório de saída |
-v | imprime o nome dos pacotes conforme compilam |
-race | compila com o detector de data race (mais lento, binário maior; para testes) |
-trimpath | remove caminhos do sistema de arquivos local do binário, para builds reproduzíveis |
-ldflags "-s -w" | remove a tabela de símbolos e as informações de depuração DWARF, deixando o binário menor |
-ldflags "-X main.version=1.4.0" | define uma variável string na hora do link |
-tags nome | inclui arquivos protegidos por uma restrição //go:build nome |
A flag -X é como a maioria dos projetos Go grava a versão no binário. Ela só funciona com variáveis string de nível de pacote (não com constantes):
go build -o app -ldflags "-X main.version=1.4.0" .
./app
version: 1.4.0
built for: linux/amd64
args: []
O binário também registra as versões dos módulos e, desde o Go 1.18, o commit do controle de versão a partir do qual foi compilado. go version -m ./app imprime essas informações, e um programa pode lê-las com runtime/debug.ReadBuildInfo.
go install
go install compila exatamente como o go build e depois move o executável para $GOBIN, ou para $GOPATH/bin quando GOBIN não está definido (por padrão $HOME/go/bin):
go install .
go env GOPATH
O uso mais comum é instalar ferramentas escritas em Go. Com @versão ele instala um programa sem mexer no seu go.mod:
go install golang.org/x/tools/gopls@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
Se depois disso o shell não encontrar a ferramenta, $HOME/go/bin não está no seu PATH. Adicione export PATH=$PATH:$(go env GOPATH)/bin ao perfil do seu shell.
Compilação cruzada com GOOS e GOARCH
Go compila para outro sistema operacional ou outra CPU a partir de qualquer máquina, sem toolchain extra. Defina duas variáveis de ambiente para o comando de build:
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 .
No PowerShell, as variáveis de ambiente são definidas de outro jeito:
$env:GOOS = "linux"; $env:GOARCH = "amd64"; go build -o app-linux .
Os pares mais comuns:
| GOOS | GOARCH | Alvo |
|---|---|---|
linux | amd64 | a maioria dos servidores e containers |
linux | arm64 | AWS Graviton, Raspberry Pi com sistema de 64 bits |
darwin | arm64 | Macs com Apple Silicon |
darwin | amd64 | Macs Intel |
windows | amd64 | Windows de 64 bits |
js | wasm | WebAssembly no navegador |
go tool dist list imprime todos os pares suportados (48 no Go 1.24).
A compilação cruzada só é fácil assim para código Go puro. Um pacote que usa cgo (código C, por exemplo alguns drivers de SQLite) precisa de um compilador C cruzado para o alvo. Na compilação cruzada o cgo vem desabilitado por padrão, e definir CGO_ENABLED=0 explicitamente também gera um binário Linux totalmente estático, que é o que você quer em uma imagem de container mínima, scratch ou distroless.
go fmt e go vet
Duas verificações devem estar em todo fluxo de trabalho, e no CI.
go fmt reescreve os arquivos no único estilo oficial: tabs, campos alinhados, espaçamento normalizado. É um atalho para gofmt -l -w:
go fmt ./...
gofmt -l . # list files that are not formatted; empty output means clean
go vet aponta código que compila mas quase certamente está errado. Formatos de Printf que não batem com os argumentos são o caso clássico:
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
O programa compila e imprime %!s(int=3) items, que é justamente o tipo de bug que o vet existe para pegar. Outras verificações do vet incluem copiar um sync.Mutex por valor, código inalcançável, struct tags com sintaxe errada e uma context.CancelFunc que nunca é chamada. go test roda um subconjunto dessas verificações automaticamente; go build não roda nenhuma.
Outros subcomandos do go
| Comando | Para que serve |
|---|---|
go test ./... | roda os testes |
go mod tidy | adiciona as dependências que faltam e remove as que não são usadas |
go get pkg@version | adiciona ou muda uma dependência |
go clean -cache | esvazia o cache de build |
go env | imprime a configuração do Go |
go doc fmt.Println | mostra a documentação no terminal |
go list -m all | lista todos os módulos do build |
Por que o segundo build é rápido
O Go guarda os pacotes compilados no cache de build (go env GOCACHE). Um novo build recompila só os pacotes cujo código ou cujas dependências mudaram, então go run . em um projeto sem alterações começa quase na hora. Se um build se comportar de forma estranha depois de trocar a versão do Go ou variáveis de ambiente, go clean -cache limpa o cache; você raramente vai precisar disso.
Perguntas frequentes
Qual a diferença entre go run e go build?
go run compila o programa em um diretório temporário, executa e descarta o binário. go build compila o programa e grava o binário no diretório atual, para você executar de novo ou copiar para outro lugar. Use go run durante o desenvolvimento e go build quando precisar do executável.
Como definir o nome do arquivo gerado pelo go build?
Use -o: go build -o myapp . grava myapp (no Windows, escreva você mesmo -o myapp.exe). Sem -o, o go build dá ao binário o nome do último elemento do caminho de import do pacote, ou do primeiro arquivo quando você passa arquivos .go, e acrescenta .exe ao compilar para Windows.
Como fazer compilação cruzada de Go para Linux ou Windows?
Defina GOOS e GOARCH para o build: GOOS=linux GOARCH=amd64 go build -o app-linux . ou GOOS=windows GOARCH=amd64 go build . (que gera um .exe). Nenhuma toolchain extra é necessária para código Go puro. go tool dist list imprime todos os pares suportados.
Onde o go install coloca o binário?
Em $GOBIN se estiver definido; senão em $GOPATH/bin, que por padrão é $HOME/go/bin. Adicione esse diretório ao seu PATH para executar as ferramentas instaladas pelo nome. go install example.com/tool@latest instala uma ferramenta sem adicioná-la ao seu módulo.
O go build executa o go vet?
Não. go build só compila. go test roda automaticamente um subconjunto das verificações do go vet, mas para o conjunto completo rode você mesmo go vet ./..., normalmente no CI ao lado de gofmt -l ..