Go Environment Variables Reference
| Official documentation: cmd/go environment variables | Source install environment |
1. Introduction
The go tool reads dozens of environment variables to control module resolution, caching, cross-compilation, the C toolchain, garbage collection, and more. You can inspect every variable in one shot with go env, or query a single one with go env GOPATH. Changes can be temporary — prefix the command with VAR=value go build — or permanent, stored in the user-level env file via go env -w VAR=value. Permanent settings are written to the file pointed at by $GOENV (default: $GOENV itself resolves to $HOME/.config/go/env on Linux/macOS and %AppData%\go\env on Windows). To remove a persistent override and fall back to the compiled-in default, run go env -u VAR. All of this works without touching your shell profile, which makes it easy to share settings across shells and CI environments consistently.
2. Module & Dependency Management
GOPATH
Default: $HOME/go (Linux/macOS) or %USERPROFILE%\go (Windows)
Set with: go env -w GOPATH=/path/to/gopath
GOPATH was historically the single workspace that held all Go source, compiled binaries, and downloaded packages. In module mode (Go 1.11+) it is much less prominent: source no longer lives here, but $GOPATH/bin is still where go install places executables, and $GOPATH/pkg/mod is the module cache. You might override it to place the cache on a larger drive or to isolate projects in CI.
# Check current value
go env GOPATH
# Move everything to a bigger disk
go env -w GOPATH=/mnt/data/go
# Temporarily use an isolated workspace for one build
GOPATH=/tmp/ci-go go build ./...
Gotcha: If
$GOPATH/binis not on your$PATH, commands installed withgo installwill be silently unreachable. Addexport PATH="$(go env GOPATH)/bin:$PATH"to your shell profile.
GOMODCACHE
Default: $GOPATH/pkg/mod
Set with: go env -w GOMODCACHE=/path/to/cache
The directory where the module cache lives. Downloaded module zip files and their extracted trees are stored here. Separating GOMODCACHE from GOPATH is useful in Docker multi-stage builds: you can mount the cache as a build-time volume without shipping it in the final image.
# Point the cache to a shared network volume for a team
go env -w GOMODCACHE=/nfs/go-mod-cache
# Docker: mount host cache into the builder stage
# Dockerfile excerpt:
# RUN --mount=type=cache,target=/root/go/pkg/mod \
# go build -o /out/app ./cmd/app
Gotcha: The module cache is read-only by design (
chmod 0555on directories). Do not try to edit files inside it; rungo clean -modcacheto wipe it instead.
GOPROXY
Default: https://proxy.golang.org,direct
Set with: go env -w GOPROXY=https://my-proxy.internal,direct
A comma-separated list of module proxy URLs consulted in order when fetching module versions. The special keyword direct means “contact the VCS origin directly”. off means “never fetch; fail if the module is not already cached”. This is the single most impactful variable for working with private registries or air-gapped networks.
# Corporate environment: hit internal proxy first, fall back to public
go env -w GOPROXY=https://goproxy.internal,https://proxy.golang.org,direct
# Air-gapped build: only use what is already in the cache
go env -w GOPROXY=off
# CI with a local Athens instance
GOPROXY=http://localhost:3000 go mod download
Gotcha: If a proxy returns a 404, the Go tool moves on to the next entry. If the proxy returns a 410 (Gone), Go treats that module version as permanently unavailable and stops trying — it will not fall through to
direct. This is intentional security behaviour.
GONOPROXY
Default: not set
Set with: go env -w GONOPROXY=*.internal.corp,github.com/myorg/*
A comma-separated list of glob patterns for module path prefixes that should bypass the proxy and be fetched directly from VCS. Patterns follow the same syntax as GOPRIVATE but only affect proxy lookup; checksum database lookup is controlled separately by GONOSUMDB.
# Bypass the proxy for all internal modules
go env -w GONOPROXY=*.corp.example.com,github.com/acme-internal/*
# Verify that a specific module would bypass the proxy
GONOPROXY=github.com/myorg/* go env GONOPROXY
GOPRIVATE
Default: not set
Set with: go env -w GOPRIVATE=github.com/myorg,*.internal
A convenience shorthand: setting GOPRIVATE=pattern is equivalent to setting both GONOPROXY=pattern and GONOSUMDB=pattern simultaneously. Use this for private modules that should never touch the public proxy or checksum database.
# Everything under your GitHub org is private
go env -w GOPRIVATE=github.com/acme/*
# Also covers an internal GitLab instance
go env -w GOPRIVATE=github.com/acme/*,gitlab.internal.corp/*
Gotcha:
GOPRIVATEis a prefix match by glob, not a substring match.github.com/acme/*matchesgithub.com/acme/foobut notgithub.com/acme-partner/foo.
GONOSUMDB
Default: not set
Set with: go env -w GONOSUMDB=*.internal,github.com/myorg/*
A comma-separated list of glob patterns for modules whose checksums should not be verified against the public checksum database (sum.golang.org). Necessary for private modules that aren’t listed in the public database, or for modules on internal registries that aren’t reachable from the internet.
# Skip checksum DB for all private modules
go env -w GONOSUMDB=github.com/acme/*,*.corp.example.com
# Confirm the setting takes effect
go env GONOSUMDB
GONOSUMCHECK
Default: not set
Set with: go env -w GONOSUMCHECK=pattern
Similar to GONOSUMDB but provides an additional layer: modules matching these patterns skip both the checksum database lookup and the local go.sum verification step entirely. Intended for extreme cases such as vendored forks or modules loaded from local disk during development. Use with caution — you lose tamper detection.
# Skip all sum checks for a local replace directive during development
go env -w GONOSUMCHECK=github.com/myorg/experimental
Gotcha: Do not set this in production CI. It silently disables the supply-chain integrity check that
go.sumprovides.
GOFLAGS
Default: not set
Set with: go env -w GOFLAGS=-mod=vendor
A space-separated list of default flags applied to every applicable go subcommand. Values here behave as if you typed them on every invocation. Useful for enforcing project-wide settings in CI without wrapper scripts.
# Always build with the race detector and verbose module output
go env -w GOFLAGS=-race
# Vendor mode everywhere (no network lookups)
go env -w GOFLAGS=-mod=vendor
# Multiple flags (quote as a single string)
go env -w GOFLAGS="-mod=vendor -trimpath"
Gotcha: Flags set in
GOFLAGSapply to everygosubcommand that accepts them. Setting-racehere meansgo test,go build, andgo runall compile with the race detector — which significantly increases binary size and slows execution. Consider setting it only in CI or test-specific scripts rather than globally.
GOWORK
Default: not set (auto-detected by walking up directories)
Set with: GOWORK=/path/to/go.work go build ./...
The path to the go.work file for a multi-module workspace. When set to off, workspace mode is disabled entirely, forcing the tool to treat each module independently — useful when you want to verify that a library works without its workspace siblings.
# Disable workspace mode for a single command
GOWORK=off go test ./...
# Point explicitly at a workspace file outside the CWD
GOWORK=/home/user/projects/go.work go build ./cmd/server
GOTOOLCHAIN
Default: local (or the value baked into the Go release)
Set with: go env -w GOTOOLCHAIN=go1.22.0
Controls which Go toolchain version is used. Starting with Go 1.21, go.mod and go.work can declare a minimum toolchain version (toolchain go1.22.0). GOTOOLCHAIN=local means “use whatever is installed locally and do not auto-download”. GOTOOLCHAIN=auto means “download and switch to the version declared in go.mod/go.work if the local version is older”. A specific version like go1.22.3 pins exactly that release.
# Use whatever is installed (no auto-download)
go env -w GOTOOLCHAIN=local
# Auto-upgrade to satisfy go.mod's toolchain directive
go env -w GOTOOLCHAIN=auto
# Pin to a specific toolchain for reproducibility in CI
GOTOOLCHAIN=go1.22.3 go build ./...
Gotcha: With
GOTOOLCHAIN=auto, the first build after updatinggo.modmay download a new toolchain fromproxy.golang.org. In air-gapped environments, setGOTOOLCHAIN=localand provision the correct Go version through your own package management.
3. Build & Toolchain
GOROOT
Default: the directory where Go is installed (detected at build time)
Set with: export GOROOT=/usr/local/go (rarely needed)
The root of the Go installation tree. The standard library lives at $GOROOT/src. Normally you never set this — the go binary knows its own location. The rare case where you might override it is when running a custom-built Go toolchain from a non-standard path.
# Inspect the current root
go env GOROOT
# Use a side-by-side Go installation (advanced)
GOROOT=/home/user/go-tip go build ./...
Gotcha: Setting
GOROOTincorrectly breaks all builds because the standard library becomes unreachable. Prefer managing multiple Go versions withgo install golang.org/dl/go1.22.0@latestor a version manager instead.
GOBIN
Default: $GOPATH/bin
Set with: go env -w GOBIN=/usr/local/bin
The directory where go install places compiled binaries. Override this to install tools into a system-wide directory or a project-local bin/ folder.
# Install tools into a project-local bin/ directory
go env -w GOBIN=$(pwd)/bin
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Install system-wide (requires write permission)
GOBIN=/usr/local/bin go install golang.org/x/tools/cmd/goimports@latest
GOTMPDIR
Default: the OS temporary directory ($TMPDIR / /tmp / %TEMP%)
Set with: go env -w GOTMPDIR=/fast-ssd/tmp
The directory used for temporary files during compilation (object files, intermediate outputs). Pointing this at a fast local SSD or a tmpfs mount can meaningfully speed up large builds.
# Use a RAM disk for faster builds on Linux
mount -t tmpfs tmpfs /mnt/ramfs -o size=4G
go env -w GOTMPDIR=/mnt/ramfs
GOCACHE
Default: $HOME/.cache/go/build (Linux/macOS) or %LocalAppData%\go-build (Windows)
Set with: go env -w GOCACHE=/path/to/cache
The build cache directory. The Go toolchain caches compiled packages here to avoid recompilation. In CI, mounting this directory between runs dramatically reduces build times.
# Check cache location
go env GOCACHE
# Redirect to a CI-friendly path
go env -w GOCACHE=/tmp/go-build-cache
# Warm the cache explicitly before building
go build -v ./... 2>/dev/null || true
# Clear the cache
go clean -cache
# GitHub Actions example: cache the build cache
# - uses: actions/cache@v4
# with:
# path: ~/.cache/go/build
# key: $-go-build-$
GOTOOLDIR
Default: $GOROOT/pkg/tool/$GOOS_$GOARCH
Set with: rarely overridden
The directory containing the low-level Go tool binaries (compile, link, asm, cover, etc.). You will almost never set this; it is surfaced mainly so build systems and IDEs can locate the compiler.
go env GOTOOLDIR
# e.g. /usr/local/go/pkg/tool/linux_amd64
GOVERSION
Default: the version string of the installed toolchain (read-only) Set with: not settable
Reports the Go version of the current toolchain. Read-only; it cannot be overridden.
go env GOVERSION
# go1.22.3
GOEXPERIMENT
Default: not set
Set with: GOEXPERIMENT=rangefunc go build ./...
A comma-separated list of experimental language or runtime features to enable. These features are not stable and may be removed or changed. Used by the Go team to ship opt-in previews before they graduate to stable.
# Enable the range-over-function iterator experiment (Go 1.22 preview)
GOEXPERIMENT=rangefunc go build ./...
# List all experiments compiled into the current toolchain
go env GOEXPERIMENT
Gotcha: Never enable experiments in production binaries. They are not covered by the Go compatibility promise and may change between patch releases.
GOENV
Default: $HOME/.config/go/env (Linux/macOS) or %AppData%\go\env (Windows)
Set with: GOENV=/path/to/custom/env go build (shell only; cannot use go env -w to change this one)
The path to the file that stores persistent go env -w settings. You can redirect this to a project-specific or CI-specific file to isolate settings. Because GOENV itself controls where the env file is read from, it cannot be stored inside that same file — you must set it as a real shell environment variable.
# Use a project-specific env file
export GOENV=$(pwd)/.goenv
go env -w GOPROXY=off
# Inspect what the env file currently contains
cat "$(go env GOENV)"
4. Cross-Compilation
Go’s cross-compilation story is exceptional: a single toolchain can produce binaries for any supported OS/architecture combination just by setting two environment variables. No additional toolchain installation is required for pure-Go code.
GOOS
Default: the host operating system
Set with: GOOS=linux go build ./...
The target operating system. Valid values include linux, darwin, windows, freebsd, openbsd, netbsd, plan9, solaris, illumos, js, wasip1, and more. The full list is in go tool dist list.
# Build a Linux binary from macOS
GOOS=linux GOARCH=amd64 go build -o app-linux ./cmd/app
# Build a Windows binary from Linux
GOOS=windows GOARCH=amd64 go build -o app.exe ./cmd/app
# List all supported OS/arch pairs
go tool dist list
GOARCH
Default: the host CPU architecture
Set with: GOARCH=arm64 go build ./...
The target CPU architecture. Common values: amd64, arm, arm64, 386, mips, mips64, ppc64, riscv64, s390x, wasm.
# Cross-compile for Raspberry Pi 4 (64-bit ARM)
GOOS=linux GOARCH=arm64 go build -o app-rpi ./cmd/app
# Cross-compile for Raspberry Pi Zero / Pi 1 (32-bit ARM v6)
GOOS=linux GOARCH=arm GOARM=6 go build -o app-rpi-zero ./cmd/app
GOARM
Default: 7
Set with: GOARM=6 go build ./...
For GOARCH=arm (32-bit ARM), selects the ARM instruction set version: 5 (ARMv5, software float), 6 (ARMv6, Raspberry Pi Zero/1), or 7 (ARMv7, Raspberry Pi 2/3 in 32-bit mode). Has no effect for other architectures.
# Raspberry Pi Zero W (ARMv6, hardware float)
GOOS=linux GOARCH=arm GOARM=6 go build -o app ./cmd/app
# ARMv5 device with no hardware FPU
GOOS=linux GOARCH=arm GOARM=5 go build -o app ./cmd/app
GOAMD64
Default: v1
Set with: GOAMD64=v3 go build ./...
For GOARCH=amd64, selects the x86-64 microarchitecture level: v1 (baseline, runs everywhere), v2 (SSE4, POPCNT — most modern x86-64 CPUs), v3 (AVX2, BMI1/BMI2 — Intel Haswell and later), v4 (AVX-512). Higher levels produce faster code but the binary will crash with an illegal-instruction fault on older CPUs.
# Fast binary for a controlled modern server fleet
GOAMD64=v3 go build -o app ./cmd/app
# Safe baseline binary for broad distribution
GOAMD64=v1 go build -o app ./cmd/app
Gotcha: Unlike
GOARM, there is no runtime fallback — av3binary simply faults on av1CPU.
GOMIPS
Default: hardfloat
Set with: GOMIPS=softfloat go build ./...
For GOARCH=mips or mips64, selects hardfloat or softfloat. Use softfloat for MIPS devices that lack an FPU.
GOOS=linux GOARCH=mips GOMIPS=softfloat go build -o app ./cmd/app
GOPPC64
Default: power8
Set with: GOPPC64=power9 go build ./...
For GOARCH=ppc64 or ppc64le, selects the PowerPC ISA level: power8 or power9. power9 enables additional vector and crypto instructions.
GOOS=linux GOARCH=ppc64le GOPPC64=power9 go build -o app ./cmd/app
GOWASM
Default: not set
Set with: GOWASM=satconv,signext go build ./...
For GOARCH=wasm, a comma-separated list of WebAssembly extensions to use. Currently recognised values: satconv (saturating conversions) and signext (sign-extension instructions). These correspond to the WebAssembly post-MVP proposals and are supported by modern browsers and runtimes.
GOOS=js GOARCH=wasm GOWASM=satconv,signext go build -o app.wasm ./cmd/app
CGO_ENABLED (cross-compilation context)
When cross-compiling, CGo is disabled by default because the host C compiler cannot target the foreign architecture without an explicit cross-compiler. For pure-Go code this is ideal — set CGO_ENABLED=0 explicitly to make the intent clear and ensure a fully static binary.
# Explicit static binary for Linux (great for Docker scratch images)
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o app ./cmd/app
See the full CGO_ENABLED entry in Section 5 for all details.
5. CGo
CGo allows Go packages to call C (and C++) code. It is powerful but adds complexity: the build requires a C toolchain, disables certain optimisations, prevents some cross-compilation scenarios, and increases link times. Each CGo variable is consulted only when CGO_ENABLED=1.
CGO_ENABLED
Default: 1 when a C compiler is available and GOOS/GOARCH match the host; 0 otherwise
Set with: go env -w CGO_ENABLED=0
The master switch for CGo. When 0, all CGo imports are rejected and the Go toolchain produces fully static binaries with no libc dependency. This is the recommended setting for Docker images built on scratch or distroless base images.
# Build a fully static binary — no libc, runs in scratch containers
CGO_ENABLED=0 go build -o app ./cmd/app
# Explicitly enable CGo (e.g. needed for sqlite3 drivers)
CGO_ENABLED=1 go build -tags cgo ./cmd/app
# Dockerfile multi-stage pattern:
# FROM golang:1.22 AS builder
# RUN CGO_ENABLED=0 GOOS=linux go build -o /app ./cmd/server
# FROM scratch
# COPY --from=builder /app /app
# ENTRYPOINT ["/app"]
Gotcha:
go testcan behave differently with CGo enabled vs disabled. The race detector (-race) requires CGo, soCGO_ENABLED=0 go test -racewill fail.
CC
Default: gcc (or clang on some systems)
Set with: CC=musl-gcc go build ./...
The C compiler used for CGo compilation. Override this when using a cross-compiler or when you want a specific compiler (e.g. musl-gcc for fully static musl-libc binaries, or arm-linux-gnueabihf-gcc for 32-bit ARM cross-compilation).
# Cross-compile CGo code for 64-bit ARM Linux
CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build ./...
# Build against musl for a smaller, fully static binary
CC=musl-gcc CGO_ENABLED=1 go build -ldflags="-linkmode external -extldflags -static" ./...
CXX
Default: g++ (or clang++)
Set with: CXX=arm-linux-gnueabihf-g++ go build ./...
The C++ compiler used when CGo code includes C++ sources or when linking against C++ libraries. Rarely set independently of CC.
CXX=clang++ CC=clang CGO_ENABLED=1 go build ./...
CGO_CFLAGS
Default: -O2 -g
Set with: CGO_CFLAGS="-I/opt/include -O3" go build ./...
Extra flags passed to the C compiler when compiling CGo C files. Use this to add include paths (-I) or optimisation flags.
# Add a custom include path for a vendored C library
CGO_CFLAGS="-I$(pwd)/vendor/mylib/include" go build ./...
# Override optimisation level
CGO_CFLAGS="-O3" go build ./...
Gotcha: These flags apply to every CGo-using package in the build, not just your own. If a transitive dependency also uses CGo, it gets these flags too. Use
#cgo CFLAGS:directives in Go source files for per-package flags instead.
CGO_CXXFLAGS
Default: -O2 -g
Set with: CGO_CXXFLAGS="-std=c++17 -I/opt/include" go build ./...
Extra flags passed to the C++ compiler. Mirrors CGO_CFLAGS but for C++ sources.
CGO_CXXFLAGS="-std=c++17" go build ./...
CGO_CPPFLAGS
Default: not set
Set with: CGO_CPPFLAGS="-DNDEBUG -DVERSION=2" go build ./...
Flags passed to the C preprocessor for both C and C++ CGo files. Use for macro definitions (-D) and include paths that apply to both languages.
CGO_CPPFLAGS="-DNDEBUG -DMYLIB_STATIC" go build ./...
CGO_LDFLAGS
Default: not set
Set with: CGO_LDFLAGS="-L/opt/lib -lmylib" go build ./...
Extra flags passed to the linker when linking CGo binaries. Use to add library search paths (-L) and library names (-l).
# Link against a system library not on the default search path
CGO_LDFLAGS="-L/opt/openssl/lib -lssl -lcrypto" go build ./...
# Statically link a C library
CGO_LDFLAGS="-L$(pwd)/vendor/mylib -lmylib -static" go build ./...
Gotcha: Flags in
CGO_LDFLAGSare passed verbatim to the linker. Thegotool validates them against a security allowlist when building withgo getor in module mode to prevent injection attacks. If you need unusual flags, use#cgo LDFLAGS:in your Go source file instead — those are whitelisted at the package level.
6. Runtime Behaviour
These variables control how a compiled Go program behaves at runtime. Most are set when running a binary, not when building it (though GOMAXPROCS can also be set in code via runtime.GOMAXPROCS()).
GOMAXPROCS
Default: number of logical CPUs on the machine
Set with: GOMAXPROCS=4 ./myapp
Controls the maximum number of OS threads that can execute Go code simultaneously. Setting it lower than the CPU count is useful for testing concurrency behaviour or for throttling a service that shares a host with other processes.
# Simulate a 2-core environment during testing
GOMAXPROCS=2 go test -race ./...
# Run production service on 8 of 32 cores
GOMAXPROCS=8 ./server
# In code: runtime.GOMAXPROCS(4)
Gotcha:
GOMAXPROCSdoes not limit goroutine count — you can have millions of goroutines withGOMAXPROCS=1. It only controls parallelism of execution. Also, cgroups-aware environments (Kubernetes, Docker) may set this automatically via theautomaxprocspackage; check before overriding.
GOMEMLIMIT
Default: not set (no limit)
Set with: GOMEMLIMIT=512MiB ./myapp
A soft memory limit for the Go runtime (introduced in Go 1.19). When the total heap size approaches this limit, the GC runs more aggressively to stay under it. Accepts values like 512MiB, 1GiB, or a plain byte count. This does not hard-cap memory — the program can still exceed the limit if GC cannot reclaim enough — but it prevents the GC from being overly lazy when memory is constrained.
# Cap a microservice in a container with 512 MiB RAM
GOMEMLIMIT=450MiB ./server # leave ~12% headroom for non-heap allocations
# Useful in Kubernetes: set to ~90% of the container memory limit
# resources:
# limits:
# memory: 512Mi
# env:
# - name: GOMEMLIMIT
# value: "460MiB"
Gotcha: Setting
GOMEMLIMITtoo close to the container’s hard limit leaves no room for stack memory, goroutine overhead, and OS-level memory. Use roughly 90% of the container limit as a rule of thumb.
GODEBUG
Default: not set
Set with: GODEBUG=gctrace=1,schedtrace=1000 ./myapp
A comma-separated list of key=value pairs that enable debug output and tweak runtime behaviours. This is a broad escape hatch used for diagnosing GC behaviour, scheduler decisions, HTTP/2 issues, TLS handshakes, and more. Key values include:
| Key | Value | Effect |
|---|---|---|
gctrace |
1 |
Print one line per GC cycle to stderr |
schedtrace |
N |
Print scheduler state every N milliseconds |
madvdontneed |
1 |
Use MADV_DONTNEED to release memory to OS sooner |
http2debug |
1 or 2 |
Log HTTP/2 framing details |
tlsdebug |
1 |
Log TLS handshake details |
asyncpreemptoff |
1 |
Disable asynchronous goroutine preemption |
clobberfree |
1 |
Overwrite freed memory (detects use-after-free) |
inittrace |
1 |
Print timing for each init() function |
# Diagnose GC pressure
GODEBUG=gctrace=1 ./myapp 2>&1 | grep ^gc
# Trace scheduler to find goroutine starvation
GODEBUG=schedtrace=500,scheddetail=1 ./myapp
# Debug TLS handshake failures
GODEBUG=tlsdebug=1 ./myapp
Gotcha:
GODEBUGoutput is written to stderr and can be extremely verbose. Never setgctrace=1in production without log-rate limiting — it can saturate disk I/O.
GOTRACEBACK
Default: single
Set with: GOTRACEBACK=all ./myapp
Controls how much information is printed when a Go program crashes (panics or receives an unhandled signal). Values:
| Value | Effect |
|---|---|
none |
No goroutine stacks, just the panic message |
single |
Stack of the goroutine that crashed (default) |
all |
Stacks of all goroutines |
system |
Like all plus internal runtime goroutines |
crash |
Like system, plus triggers a core dump if possible |
# Get full picture during a crash investigation
GOTRACEBACK=all ./myapp
# Generate a core dump for post-mortem analysis with dlv
GOTRACEBACK=crash ./myapp
GOGC
Default: 100
Set with: GOGC=200 ./myapp or GOGC=off ./myapp
Sets the initial garbage-collection target percentage. A value of 100 means the GC triggers a cycle when the live heap has grown by 100% since the last collection (i.e. it doubles). Increasing GOGC reduces GC frequency at the cost of higher peak memory usage. GOGC=off disables automatic GC entirely (useful for benchmarks and short-lived batch programs). GOGC=200 is a common production tuning choice for throughput-sensitive services.
# Less GC, more memory — good for CPU-bound services
GOGC=200 ./server
# Disable GC for a short-lived batch job
GOGC=off ./batch-import --input data.csv
# Aggressive GC for memory-constrained environments
GOGC=50 ./server
# In code: debug.SetGCPercent(200)
Gotcha: Since Go 1.19,
GOMEMLIMITis usually a better knob thanGOGCfor container environments because it gives absolute bounds rather than relative ones. Consider using both together:GOMEMLIMITfor ceiling safety,GOGCfor throughput tuning.
7. Security & Privacy
GONOSUMDB
See Section 2 for the full entry.
GONOSUMCHECK
See Section 2 for the full entry.
GOPRIVATE (cross-reference)
See Section 2 for the full entry. GOPRIVATE is the recommended single variable for private modules: it sets both GONOPROXY and GONOSUMDB simultaneously.
GOTELEMETRY
Default: local
Set with: go env -w GOTELEMETRY=off
Controls whether the Go toolchain uploads usage telemetry to Google. Introduced in Go 1.23. Values:
| Value | Effect |
|---|---|
off |
No data collected or uploaded |
local |
Data collected locally but not uploaded (default) |
on |
Data collected and uploaded to telemetry.go.dev |
# Disable all telemetry (common in enterprise/air-gapped environments)
go env -w GOTELEMETRY=off
# Opt into uploading to help the Go team
go env -w GOTELEMETRY=on
# Check current mode
go env GOTELEMETRY
Gotcha: Telemetry is opt-in for uploads (
onmust be set explicitly). Thelocaldefault collects data to disk without transmitting it, which allows thego telemetrycommand to show local statistics.
8. Debugging & Profiling
This section cross-references variables from other sections and highlights how they combine for debugging and profiling workflows.
GOFLAGS (cross-reference for debugging)
See Section 2. Common debugging uses:
# Always build with race detector during development
go env -w GOFLAGS=-race
# Always enable coverage instrumentation
go env -w GOFLAGS=-cover
GOGC (cross-reference)
See Section 6. For benchmarking, disable GC to get stable measurements:
GOGC=off go test -bench=. -benchmem ./...
GOMAXPROCS (cross-reference)
See Section 6. For profiling single-threaded vs multi-threaded performance:
# Profile with a single thread to isolate algorithmic cost
GOMAXPROCS=1 go test -bench=. -cpuprofile=cpu.prof ./...
go tool pprof cpu.prof
Combined example: full observability during a load test
GODEBUG=gctrace=1,schedtrace=1000 \
GOMAXPROCS=4 \
GOGC=200 \
GOMEMLIMIT=1GiB \
./server 2>runtime-debug.log &
# In another terminal
go tool pprof http://localhost:6060/debug/pprof/heap
9. Quick Reference Table
| Variable | Default | One-line description |
|---|---|---|
GOPATH |
$HOME/go |
Workspace root; bin/ subdir holds installed binaries |
GOROOT |
Go install dir | Location of the Go standard library and toolchain |
GOMODCACHE |
$GOPATH/pkg/mod |
Directory where downloaded module zips are cached |
GOPROXY |
https://proxy.golang.org,direct |
Ordered list of module proxy URLs |
GONOPROXY |
not set | Module path globs to fetch directly, bypassing the proxy |
GOPRIVATE |
not set | Shorthand for setting both GONOPROXY and GONOSUMDB |
GONOSUMDB |
not set | Module path globs to skip checksum database verification |
GONOSUMCHECK |
not set | Module path globs to skip all checksum verification |
GOFLAGS |
not set | Default flags applied to every go subcommand |
GOWORK |
auto-detected | Path to go.work file; off disables workspace mode |
GOTOOLCHAIN |
local |
Which Go toolchain version to use; auto downloads if needed |
GOBIN |
$GOPATH/bin |
Directory where go install places binaries |
GOTMPDIR |
OS temp dir | Directory for temporary files during compilation |
GOCACHE |
~/.cache/go/build |
Build artifact cache directory |
GOTOOLDIR |
$GOROOT/pkg/tool/… |
Location of internal compiler tools (compile, link, asm) |
GOVERSION |
toolchain version | Read-only: version string of the installed toolchain |
GOEXPERIMENT |
not set | Comma-separated list of experimental features to enable |
GOENV |
~/.config/go/env |
Path to the persistent go env -w settings file |
GOOS |
host OS | Target operating system for compilation |
GOARCH |
host CPU arch | Target CPU architecture for compilation |
GOARM |
7 |
ARM sub-architecture version (5, 6, or 7) |
GOAMD64 |
v1 |
x86-64 microarchitecture level (v1–v4) |
GOMIPS |
hardfloat |
MIPS float ABI: hardfloat or softfloat |
GOPPC64 |
power8 |
PowerPC ISA level: power8 or power9 |
GOWASM |
not set | WebAssembly extensions (satconv, signext) |
CGO_ENABLED |
1 (if C compiler present) |
Master switch for CGo; 0 produces fully static binaries |
CC |
gcc |
C compiler used by CGo |
CXX |
g++ |
C++ compiler used by CGo |
CGO_CFLAGS |
-O2 -g |
Extra flags for the C compiler during CGo builds |
CGO_CXXFLAGS |
-O2 -g |
Extra flags for the C++ compiler during CGo builds |
CGO_CPPFLAGS |
not set | Preprocessor flags for both C and C++ CGo files |
CGO_LDFLAGS |
not set | Extra linker flags for CGo binaries |
GOMAXPROCS |
number of logical CPUs | Maximum OS threads executing Go code in parallel |
GOMEMLIMIT |
not set | Soft heap memory limit for the runtime (e.g. 512MiB) |
GODEBUG |
not set | Comma-separated runtime debug knobs (gctrace, schedtrace, …) |
GOTRACEBACK |
single |
Verbosity of stack traces on crash |
GOGC |
100 |
GC trigger percentage; off disables automatic GC |
GOTELEMETRY |
local |
Toolchain usage telemetry: off, local, or on |
10. Common Recipes
1. Offline / air-gapped build (all dependencies pre-downloaded)
# Vendor dependencies first (run once with network access)
go mod vendor
# Then build offline — no proxy, no sum DB, use vendor/
GOFLAGS=-mod=vendor GOPROXY=off GONOSUMCHECK=* go build ./...
2. Cross-compile for Raspberry Pi 4 (64-bit ARM Linux)
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 \
go build -o app-rpi4 ./cmd/app
# Copy to Pi:
scp app-rpi4 pi@raspberrypi.local:~/app
3. Cross-compile for Raspberry Pi Zero / Pi 1 (32-bit ARM v6)
GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=0 \
go build -o app-rpi-zero ./cmd/app
4. Fully static binary for a Docker scratch image
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags="-s -w" -o app ./cmd/app
# Dockerfile:
# FROM scratch
# COPY app /app
# ENTRYPOINT ["/app"]
5. Point builds at a private module proxy (e.g. Athens or Artifactory)
go env -w GOPROXY=https://goproxy.corp.example.com,direct
go env -w GOPRIVATE=github.com/corp-org/*,gitlab.internal.corp/*
go env -w GONOSUMDB=github.com/corp-org/*,gitlab.internal.corp/*
6. Speed up CI with build and module caches
# GitHub Actions workflow snippet:
# - uses: actions/cache@v4
# with:
# path: |
# ~/.cache/go/build
# ~/go/pkg/mod
# key: $-go-$
# Or set cache paths explicitly:
go env -w GOCACHE=/ci/cache/go/build
go env -w GOMODCACHE=/ci/cache/go/pkg/mod
7. Run with the race detector (without setting GOFLAGS globally)
go test -race ./...
go run -race ./cmd/app
go build -race -o app-race ./cmd/app && ./app-race
8. Profile GC and scheduler during a load test
GODEBUG=gctrace=1,schedtrace=2000 GOMAXPROCS=4 \
./server 2>runtime.log
# Parse GC lines:
grep '^gc' runtime.log | awk '{print $3, $5, $9}'
9. Build a musl-linked static binary on Linux (for Alpine containers)
# Requires musl-tools: apt-get install musl-tools
CC=musl-gcc CGO_ENABLED=1 \
go build -ldflags="-linkmode external -extldflags '-static'" \
-o app ./cmd/app
ldd app # should print "not a dynamic executable"
10. Pin the toolchain for reproducible CI builds
# In go.mod:
# go 1.22.3
# toolchain go1.22.3
# In CI shell:
GOTOOLCHAIN=go1.22.3 go build ./...
# Or permanently:
go env -w GOTOOLCHAIN=go1.22.3