Go environment variables: getenv, setenv, lookup, go env, and .env files

Go environment variables and golang environment variables: golang get environment variable with LookupEnv, golang set environment variable with Setenv, go env vs process env (golang env, go env variables), env golang and os.getenv golang, optional golang env file with godotenv, Viper pointer, and environment variables best practices.

Published

Updated

Read time 5 min read

Reviewed byDeepak Prasad

Go environment variables: getenv, setenv, lookup, go env, and .env files

Topics such as go environment variables, environment variables golang, golang environment variables, go env variables, and golang env variables sit on two layers: the Unix-style process environment your binary reads with os.Getenv (often searched as os.getenv golang or golang get environment variable) and os.LookupEnv, and the go env CLI that reports the Go toolchain settings (GOOS, GOMODCACHE, module paths)—what people sometimes mean by golang env or go env alone. This guide covers golang set environment variable with os.Setenv, clearing keys with os.Unsetenv (golang unset variable at the process level), when to prefer LookupEnv, how go env fits in, optional golang env file loading with godotenv, where Viper fits for larger configs, and environment variables best practices. For where Linux sets variables globally, see where to set environment variables in Linux.

Tested with Go 1.24 on Linux.


Read: os.Getenv and os.LookupEnv

os.Getenv returns a string; if the key is missing, it returns "", same as when the key exists but is empty—so you cannot tell those cases apart. os.LookupEnv returns (value string, ok bool); ok is false when the variable is unset.

go
package main

import (
	"fmt"
	"os"
)

func main() {
	shell := os.Getenv("SHELL")
	fmt.Printf("SHELL=%q\n", shell)

	if v, ok := os.LookupEnv("HOME"); ok {
		fmt.Println("HOME set, length", len(v))
	}
}
Output

Run locally: you should see SHELL quoted (possibly empty on minimal environments) and a line about HOME when it is set.


Set and unset: os.Setenv / os.Unsetenv

os.Setenv(key, value) updates the current process. os.Unsetenv removes the key. Use os.Clearenv only when you intentionally wipe the environment (rare, security-sensitive).

go
package main

import (
	"fmt"
	"os"
)

func main() {
	os.Setenv("MYAPP_MODE", "staging")
	fmt.Println(os.Getenv("MYAPP_MODE"))
	os.Unsetenv("MYAPP_MODE")
	fmt.Printf("after unset: %q\n", os.Getenv("MYAPP_MODE"))
}
Output

You should see staging then an empty quoted string after unset.


go env (toolchain “golang env”)

The go env command prints Go build configuration, not your whole shell. It answers questions like which GOOS this toolchain targets without importing os in code.

text
go env GOOS GOARCH GOMODCACHE

On a typical Linux machine you should see three lines: linux, amd64 (or your arch), and a module cache path under your home directory. Values vary by install. Use this when docs say go env variables in the sense of the Go tool, not app-level environment variables golang reads with os.Getenv.


List: os.Environ

os.Environ returns []string entries in the form key=value. Treat it as sensitive: do not log the full slice in production. Prefer known keys or a MYAPP_ prefix filter.

go
package main

import (
	"fmt"
	"os"
	"strings"
)

func main() {
	for _, kv := range os.Environ() {
		if strings.HasPrefix(kv, "MYAPP_") {
			fmt.Println(kv)
		}
	}
}
Output

With no MYAPP_* variables set, this may print nothing—that is expected.


Optional: golang env file, godotenv, and Viper

For a golang env file (often named .env or app.env), teams keep non-secret defaults beside the repo. Golang get environment variable still flows through the process table: loaders copy file contents into the environment at startup, then you use LookupEnv as usual.

.env layout conventions

  • One KEY=value per line; uppercase with underscores (for example DB_HOST) is a common convention for env-style names.
  • Put comments on their own lines; avoid trailing inline comments on the same line as a value if your parser is strict.
  • Simple values usually need no quotes; if you use quotes, stay consistent with what your loader documents.

Load .env with godotenv

For local development, load a file once with github.com/joho/godotenv. This is not in the standard library—add it to your module and keep real secrets out of git.

text
go mod init example.com/myapp
go get github.com/joho/godotenv
go
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/joho/godotenv"
)

func main() {
	if err := godotenv.Load(".env"); err != nil {
		log.Fatal(err)
	}
	fmt.Println("PORT=", os.Getenv("PORT"))
}

Example .env (dummy values only):

text
PORT=8080
MYAPP_ENV=dev

Run locally after creating .env; you should see the printed PORT value.

Viper for layered configuration

When you merge files, flags, and environment overrides, use Viper for structured loading and unmarshaling into structs. For small services, godotenv plus os.LookupEnv is often enough.


Environment variables best practices

  • Prefer LookupEnv for required keys so “missing” is not confused with empty.
  • Use one place to load config at startup; pass values down instead of calling os.Getenv from every package.
  • Do not commit .env with secrets; use .env.example without real credentials.
  • In containers and systemd units, inject config with real env vars or secret mounts rather than baking values into images.
  • Separate development and production sources of truth; twelve-factor style config keeps apps portable.

Summary

Go environment variables and golang environment variables at runtime use os.Getenv, os.LookupEnv (for reliable golang get environment variable checks), os.Setenv and os.Unsetenv (for golang set environment variable and clearing), and careful use of os.Environ. Go env and golang env in the toolchain sense mean the go env command, not your app shell. A golang env file does nothing until you load it—godotenv or Viper bridge file content into the process environment or into structs. Follow environment variables best practices for secrets and logging. For app-wide mutable state that is not env-based, see global variables in Go; for reading arbitrary files, see read file into variable.


References


Frequently Asked Questions

1. What is the difference between go env and os.Getenv in Go?

go env is a CLI that prints the Go toolchain configuration (GOOS, GOCACHE, etc.); os.Getenv reads the current process environment inside your program—searches for go env variables often mean one or both depending on context.

2. When should I use os.LookupEnv instead of os.Getenv?

Use LookupEnv when you must tell unset from set-to-empty-string; Getenv returns an empty string in both cases, so LookupEnv avoids that ambiguity for required configuration.

3. Does os.Setenv affect child processes?

It updates the environment of your process; child processes inherit the environment present when you start them, not retroactively for already running children.

4. Is it safe to commit a .env file?

No for real secrets; keep .env out of version control, provide .env.example with dummy values, and load files only in development or via a secret manager in production.

5. How do I avoid logging every variable from os.Environ?

Never print the full slice in production logs; filter by a stable prefix such as MYAPP_ or iterate only keys you expect.

6. How do I load a golang env file so golang get environment variable works?

Go does not read .env automatically; call godotenv.Load at startup to copy keys into the process environment, or use Viper to read the file into a struct, then read values with LookupEnv or the Viper API.

7. What is env golang compared to go env?

env golang usually means the process environment for your application; go env prints the Go tools own settings—they answer different questions.
Antony Shikubu

Systems Integration Engineer

Highly skilled software developer with expertise in Python, Golang, and AWS cloud services.