The go env Command
Learn how to inspect set and manage Go environment variables using the go env command
The go env command is your window into how the Go toolchain sees its own configuration. It prints the environment variables that go build, go test, go run, and every other subcommand will actually use — which is not always the same as what your operating system’s environment says. Being able to read and change these values is essential for debugging builds, switching between projects, and working with private module registries.
How go env Differs from System Environment Variables
Every Go environment variable — GOPATH, GOROOT, GOPROXY, GOOS, and the rest — has a hard‑coded default inside the Go tool itself. If your OS shell has not set that variable, the tool falls back to the default. If you have set an OS environment variable, that value wins. And since Go 1.13, a third layer exists: a persistent file that lets you set values without touching your shell profile at all.
go env prints the final resolved value after merging all three layers. This is why go env GOPATH might show a path you never explicitly exported — it’s the default.
Viewing Environment Variables
Listing All Variables
Run go env with no arguments to see every variable Go tracks, printed in a form your shell can evaluate.
go env
Example output (truncated):
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/you/.cache/go-build'
GOENV='/home/you/.config/go/env'
GOEXE=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOOS='linux'
GOPATH='/home/you/go'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.23.0'
...
Notice the output uses shell‑quoting rules: values containing special characters are single‑quoted, empty values are just two single quotes with nothing between them. This format is designed so you can capture the output and source it directly in a shell script if needed.
The output changes based on your operating system and architecture. On Windows, go env prints set NAME=VALUE lines instead of NAME='VALUE'.
Host vs. Target Variables:
Some variables appear twice: GOOS is the target operating system your program will be compiled for, while GOHOSTOS is the OS of the machine running the compiler itself. When you cross‑compile, these two will differ.
Querying a Single Variable
If you only care about one value, pass the variable name as an argument:
go env GOMODCACHE
This prints just the value, with no extra formatting:
/home/you/go/pkg/mod
That plain‑text output is perfect for scripts. You can write export GOMODCACHE=$(go env GOMODCACHE) without parsing anything.
JSON Output for Automation
Since Go 1.13, you can request machine‑readable output with the -json flag:
go env -json GOPATH GOROOT GOPROXY
This returns a JSON object mapping variable names to their values:
{
"GOPATH": "/home/you/go",
"GOROOT": "/usr/local/go",
"GOPROXY": "https://proxy.golang.org,direct"
}
Pass no variable names to dump everything as one large JSON object. Automation scripts, CI pipelines, and editor integrations often use this to discover the Go environment without fragile parsing.
Setting Persistent Environment Values
go env is not just a viewer — it can also write settings that persist across terminal sessions. The flag -w writes a NAME=VALUE entry to a configuration file that the Go tool reads on every invocation.
go env -w GOPROXY=https://my.internal.proxy,direct
After running this, go env GOPROXY returns https://my.internal.proxy,direct, even in a brand‑new shell that never ran export GOPROXY=....
The -w flag accepts multiple key‑value pairs at once:
go env -w GOPROXY=direct GONOSUMDB=*.corp.example.com
If you set a variable that already exists, the old value is overwritten. There is no confirmation prompt — the command trusts you.
Verifying a Persistent Change:
After using go env -w, always verify with go env VARNAME. If the new value does not appear, check whether an OS environment variable of the same name is still set — OS variables override the stored file. That precedence is covered later in this document.
Variables that are commonly set with -w include GOPROXY, GOPRIVATE, GONOSUMDB, and GONOPROXY — the ones that control module download behavior and are often project‑specific or organization‑wide. You would rarely persist GOOS or GOARCH globally, because those are typically set per build command, not permanently.
Unsetting Variables
To remove a persistent setting and fall back to the default, use the -u flag:
go env -u GOPROXY
After unsetting, go env GOPROXY prints the default proxy URL again. If an OS environment variable with the same name exists, unsetting the persistent entry merely lets the OS value take over — the default will not appear as long as an OS override is present.
You can unset multiple variables in one command, just like with -w.
Unsetting does not clear OS environment variables:
go env -u only removes the entry from the persistent file. If you previously ran export GOPROXY=... in your shell, that value will still be active. To remove an OS‑level setting, you must unset it in your shell profile (~/.bashrc, ~/.zshrc, etc.) and start a new shell, or explicitly unset it in the current session.
Where Persistent Settings Are Stored
The file that go env -w writes to is called the go env file, and its location is given by the GOENV variable itself. You can find it with:
go env GOENV
By default, the file path depends on your platform:
On Linux, GOENV defaults to:
~/.config/go/env
The directory is created automatically the first time you run go env -w.
You can override this path by setting the GOENV OS environment variable yourself. That can be useful in CI environments where you want to point to a shared configuration file.
The file itself is plain text, with one NAME=VALUE line per variable:
GOPROXY=https://proxy.golang.org,direct
GONOSUMDB=*.example.com
Editing this file directly is safe as long as you keep the format intact. However, the go env -w command is the intended interface and is less error‑prone than a manual edit.
Do not mix manual edits with go env -w in the same session:
The Go command caches the file’s contents in memory during its process lifetime. If you edit the file by hand and then run go env -w in the same terminal session without restarting the Go process, the cached version may overwrite your manual changes. Use one method or the other, or simply stick to go env -w.
Understanding Precedence: OS, File, and Defaults
When the Go tool needs a variable, it follows a fixed order of priority:
- OS environment variable — if
GOPROXYis set in your shell, that wins. - Go env file — the persistent file described above.
- Hard‑coded default — built into the Go binary.
go env shows you the final result after this cascade. This means that if you have both an OS export and a persistent setting for the same variable, the OS export hides the persistent one entirely. That can be confusing if you expect go env -w to take effect immediately — it will, but only if no OS variable overshadows it.
A simple test:
export GOPROXY=direct
go env -w GOPROXY=https://proxy.golang.org,direct
go env GOPROXY # prints "direct"
After you unset the OS variable or start a new shell, the persistent value takes over:
unset GOPROXY
go env GOPROXY # prints "https://proxy.golang.org,direct"
This precedence is why many developers prefer to avoid exporting Go variables in their shell profiles and instead rely on go env -w for settings they always want active. It keeps the configuration visible through go env without surprises from a stale shell session.
A Practical Workflow Using go env
Imagine you join a team that maintains a private Go module repository hosted on git.internal.company.com. To avoid leaking internal module names to public proxies and checksum databases, you need to configure GOPRIVATE and GONOSUMDB. Here is a step‑by‑step sequence:
Check your current values
Start by confirming that no conflicting settings exist:
go env GOPRIVATE GONOSUMDB
If both are empty, you are starting from defaults. If not, note any existing values so you can decide whether to append to them or replace them.
Set the private module patterns
Use go env -w to persist the patterns:
go env -w GOPRIVATE=git.internal.company.com/* GONOSUMDB=git.internal.company.com/*
The * wildcard matches all repositories under that host. You could also list multiple patterns separated by commas.
Verify the settings
Confirm the Go tool sees the new values:
go env GOPRIVATE GONOSUMDB
You should see your patterns. If an OS environment variable still overrides one of them, the go env output will show the OS value instead.
Test a private fetch
Try fetching a known private module to ensure no proxy or checksum errors occur:
go get git.internal.company.com/team/shared-lib@latest
A successful fetch confirms the configuration works.
This workflow uses only go env and go get; no editing of shell profiles is needed. If you later switch projects, you can go env -u those variables and set new ones appropriate for the next codebase.
Common Mistakes
- Assuming
go env -woverrides OS exports. It does not. Always rungo env VARto see what the toolchain will actually use. If you see an unexpected value, check your shell withecho $VARNAME(orecho %VARNAME%on Windows). - Forgetting to unset variables after changing teams. Persistent settings survive terminal restarts. When you stop working on a private project, run
go env -u GOPRIVATEand similar variables to avoid leaking requests to the wrong proxy or checksum database. - Editing the
go envfile whilegois running. Some IDEs and language servers start Go processes that stay alive. A manual edit can be overwritten by a latergo env -wor by a background tool that has the old state cached. Prefergo env -wto stay safe. - Setting
GOROOTwithout a clear reason. Most installations detect their root automatically. SettingGOROOTincorrectly can breakgo buildentirely. Usego env GOROOTto see what Go currently detects, and only change it if you have installed Go in a non‑standard location and the detection fails.
Summary
go env is the single source of truth for how the Go toolchain is configured at any moment. Use it to inspect variables, set them persistently with -w, and unset them with -u. The command’s output reflects the merged result of OS exports, the persistent environment file, and Go’s internal defaults, giving you complete visibility into what every go build and go test will see.
The persistent environment file, located at the path shown by go env GOENV, is a lightweight alternative to polluting your shell profile with exports. It keeps your Go‑specific configuration separate and portable. Combined with the go env -json flag, you can script environment discovery reliably across different machines.