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:

  1. OS environment variable — if GOPROXY is set in your shell, that wins.
  2. Go env file — the persistent file described above.
  3. 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:

1

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.

2

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.

3

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.

4

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 -w overrides OS exports. It does not. Always run go env VAR to see what the toolchain will actually use. If you see an unexpected value, check your shell with echo $VARNAME (or echo %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 GOPRIVATE and similar variables to avoid leaking requests to the wrong proxy or checksum database.
  • Editing the go env file while go is running. Some IDEs and language servers start Go processes that stay alive. A manual edit can be overwritten by a later go env -w or by a background tool that has the old state cached. Prefer go env -w to stay safe.
  • Setting GOROOT without a clear reason. Most installations detect their root automatically. Setting GOROOT incorrectly can break go build entirely. Use go env GOROOT to 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.