How does cross-compilation work in Go?

4 minintermediategocross-compilationGOOSGOARCH

Quick Answer

Go supports cross-compilation natively, with no separate toolchain or emulator needed, through the GOOS and GOARCH environment variables: GOOS=linux GOARCH=amd64 go build produces a Linux/x86-64 binary even when run from a Mac or Windows machine. This works because the Go toolchain ships pre-built standard library packages for every supported OS/architecture combination, and the compiler itself is capable of targeting any of them directly. This is dramatically simpler than cross-compilation in languages like C/C++, which typically require a separate cross-compiler toolchain and target-specific system headers/libraries to be installed and configured for each target platform.

Detailed Answer

Cross-compiling a Go program is often just setting two environment variables, no extra tools required.

Basic cross-compilation

GOOS=linux GOARCH=amd64 go build -o myapp-linux-amd64 .
GOOS=darwin GOARCH=arm64 go build -o myapp-mac-arm64 .
GOOS=windows GOARCH=amd64 go build -o myapp-windows-amd64.exe .

Each of these produces a native, statically-linked-by-default binary for its target platform, buildable from any single development machine.

Listing supported combinations

go tool dist list
darwin/amd64
darwin/arm64
linux/386
linux/amd64
linux/arm64
windows/amd64
...dozens more...

Why this is simpler than in C/C++

C/C++ cross-compilation typically needs:
  - A separate cross-compiler toolchain per target (e.g., a Linux-hosted
    compiler that targets ARM)
  - Target-specific system headers and libraries installed
  - Careful handling of dynamic linking against the target's C library

Go cross-compilation needs:
  - GOOS and GOARCH set
  - That's it, in the common case

Go's standard library ships pre-compiled for every supported platform combination, and Go binaries are statically linked by default (aside from cgo-using code), so there's no target-side system library dependency to manage in the typical case.

The cgo caveat

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .

If your code uses cgo (calling into C libraries), cross-compilation gets much harder, since it genuinely needs a C cross-compiler for the target platform. Setting CGO_ENABLED=0 disables cgo entirely, forcing a pure-Go build, which is why minimal container images for Go services often explicitly set this to guarantee simple, dependency-free cross-compilation.