go run compila y ejecuta un programa en un solo paso y no conserva ningún binario. go build compila y deja un ejecutable en el directorio actual. go install compila y coloca el ejecutable en $HOME/go/bin. Los tres compilan a código máquina nativo; ninguno interpreta nada.
| Comando | Compila | Ejecuta | Conserva un binario | Dónde va el binario |
|---|---|---|---|---|
go run . | sí | sí | no | directorio temporal, que se borra después |
go build | sí | no | sí | directorio actual (o -o path) |
go install | sí | no | sí | $GOBIN, si no $GOPATH/bin |
El siguiente programa es el que se usa en los ejemplos de esta página. El editor lo ejecuta igual que lo haría go run.
go run
go run recibe un paquete (normalmente ., el directorio actual) o una lista de archivos .go:
go run .
go run main.go
go run ./cmd/server
Todo lo que va después del paquete se pasa a tu programa como argumentos:
go run . --port 8080 verbose
version: dev
built for: linux/amd64
args: [--port 8080 verbose]
Prefiere go run . a go run main.go. Nombrar un archivo compila solo ese archivo, así que en cuanto el paquete tiene un segundo archivo, las funciones definidas allí se marcan como undefined. La página de paquetes e imports explica ese error en detalle.
go run también ejecuta un programa remoto en una versión concreta sin instalarlo, lo que viene bien para los generadores de código:
go run golang.org/x/tools/cmd/stringer@v0.30.0 -type=Color
go build
go build compila el paquete del directorio actual. Para un paquete main escribe un ejecutable; para un paquete de librería compila, informa de errores y descarta el resultado.
go mod init example.com/hello
go build
ls
go.mod hello main.go
El nombre del binario sigue estas reglas:
| Ejecutas | Nombre del binario |
|---|---|
go build en el módulo example.com/hello | hello |
go build ./cmd/server | server |
go build main.go | main (por el primer archivo) |
go build -o bin/app . | bin/app |
cualquiera de los anteriores con GOOS=windows | el mismo nombre más .exe |
Dos formas más que usarás constantemente:
go build ./... # compile every package in the module
go vet ./... # static checks, covered below
./... significa "este directorio y todos los que cuelgan de él". go build ./... con varios paquetes main no escribe ningún binario; es una comprobación rápida de que todo compila.
Flags de compilación útiles
| Flag | Qué hace |
|---|---|
-o name | archivo o directorio de salida |
-v | imprime los nombres de los paquetes a medida que se compilan |
-race | compila con el detector de carreras de datos (más lento, binario más grande; para pruebas) |
-trimpath | quita las rutas locales del sistema de archivos del binario, para compilaciones reproducibles |
-ldflags "-s -w" | elimina la tabla de símbolos y la información de depuración DWARF, lo que reduce el binario |
-ldflags "-X main.version=1.4.0" | asigna una variable string en tiempo de enlazado |
-tags name | incluye los archivos protegidos por una restricción //go:build name |
El flag -X es la forma en que la mayoría de proyectos Go graban una versión en el binario. Solo funciona con variables string a nivel de paquete (no con constantes):
go build -o app -ldflags "-X main.version=1.4.0" .
./app
version: 1.4.0
built for: linux/amd64
args: []
El binario también registra las versiones de sus módulos y, desde Go 1.18, el commit del VCS a partir del que se compiló. go version -m ./app los imprime, y un programa puede leerlos con runtime/debug.ReadBuildInfo.
go install
go install compila exactamente igual que go build y luego mueve el ejecutable a $GOBIN, o a $GOPATH/bin cuando GOBIN no está definido (por defecto $HOME/go/bin):
go install .
go env GOPATH
Su uso más común es instalar herramientas escritas en Go. Con @version instala un programa sin tocar tu go.mod:
go install golang.org/x/tools/gopls@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
Si después el shell no encuentra una herramienta, $HOME/go/bin no está en tu PATH. Añade export PATH=$PATH:$(go env GOPATH)/bin al perfil de tu shell.
Compilación cruzada con GOOS y GOARCH
Go puede compilar para otro sistema operativo u otra CPU desde cualquier máquina, sin toolchain extra. Define dos variables de entorno para el comando de compilación:
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 .
En PowerShell las variables de entorno se definen de otra forma:
$env:GOOS = "linux"; $env:GOARCH = "amd64"; go build -o app-linux .
Las combinaciones más habituales:
| GOOS | GOARCH | Destino |
|---|---|---|
linux | amd64 | la mayoría de servidores y contenedores |
linux | arm64 | AWS Graviton, Raspberry Pi con un sistema de 64 bits |
darwin | arm64 | Macs con Apple Silicon |
darwin | amd64 | Macs con Intel |
windows | amd64 | Windows de 64 bits |
js | wasm | WebAssembly en un navegador |
go tool dist list imprime todas las combinaciones admitidas (48 en Go 1.24).
La compilación cruzada es así de fácil solo para código Go puro. Un paquete que usa cgo (código C, por ejemplo algunos drivers de SQLite) necesita un compilador cruzado de C para el destino. Al compilar para otra plataforma, cgo está desactivado por defecto, y definir CGO_ENABLED=0 explícitamente te da además un binario de Linux totalmente estático, que es lo que quieres en una imagen de contenedor mínima scratch o distroless.
go fmt y go vet
Dos comprobaciones deberían estar en cualquier flujo de trabajo, y en CI.
go fmt reescribe los archivos en el único estilo oficial: tabuladores, campos alineados, espaciado normalizado. Es un envoltorio de gofmt -l -w:
go fmt ./...
gofmt -l . # list files that are not formatted; empty output means clean
go vet informa del código que compila pero casi seguro que está mal. Las discrepancias de formato de Printf son el caso clásico:
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
El programa compila e imprime %!s(int=3) items, justo el tipo de bug que vet existe para detectar. Otras comprobaciones de vet incluyen copiar un sync.Mutex por valor, código inalcanzable, struct tags con sintaxis incorrecta y un context.CancelFunc al que nunca se llama. go test ejecuta automáticamente una parte de estas comprobaciones; go build no ejecuta ninguna.
Otros subcomandos de go
| Comando | Para qué sirve |
|---|---|
go test ./... | ejecutar los tests |
go mod tidy | añadir las dependencias que faltan y quitar las que no se usan |
go get pkg@version | añadir o cambiar una dependencia |
go clean -cache | vaciar la caché de compilación |
go env | imprimir la configuración de Go |
go doc fmt.Println | mostrar la documentación en la terminal |
go list -m all | listar todos los módulos de la compilación |
Por qué la segunda compilación es rápida
Go guarda los paquetes compilados en la caché de compilación (go env GOCACHE). Una recompilación solo vuelve a compilar los paquetes cuyo código o dependencias cambiaron, así que go run . sobre un proyecto sin cambios arranca casi al instante. Si alguna vez una compilación se comporta de forma extraña después de cambiar de versión de Go o de variables de entorno, go clean -cache la vacía; rara vez debería hacerte falta.
Preguntas frecuentes
¿Qué diferencia hay entre go run y go build?
go run compila el programa en un directorio temporal, lo ejecuta y tira el binario. go build compila el programa y escribe el binario en el directorio actual para que puedas ejecutarlo de nuevo o copiarlo a otro sitio. Usa go run mientras desarrollas y go build cuando necesites el ejecutable.
¿Cómo cambio el nombre del archivo de salida de go build?
Usa -o: go build -o myapp . escribe myapp (en Windows, escribe tú -o myapp.exe). Sin -o, go build nombra el binario según el último elemento de la ruta de import del paquete, o según el primer archivo cuando le pasas archivos .go, y añade .exe al compilar para Windows.
¿Cómo compilo Go para Linux o Windows desde otro sistema?
Define GOOS y GOARCH para la compilación: GOOS=linux GOARCH=amd64 go build -o app-linux . o GOOS=windows GOARCH=amd64 go build . (que produce un .exe). Para código Go puro no hace falta ninguna toolchain extra. go tool dist list imprime todas las combinaciones admitidas.
¿Dónde deja go install el binario?
En $GOBIN si está definido; si no, en $GOPATH/bin, que por defecto es $HOME/go/bin. Añade ese directorio a tu PATH para ejecutar por su nombre las herramientas instaladas. go install example.com/tool@latest instala una herramienta sin añadirla a tu módulo.
¿go build ejecuta go vet?
No. go build solo compila. go test ejecuta automáticamente una parte de las comprobaciones de go vet, pero para el conjunto completo ejecuta tú go vet ./..., normalmente en CI junto a gofmt -l ..