Environment Variables in Go
Using os.Getenv and envconfig packages
Reading Environment Variables
Go provides environment variable access through the os package. The two primary functions are os.Getenv and os.LookupEnv:
package main
import (
"fmt"
"os"
)
func main() {
// Returns empty string if not set
dbURL := os.Getenv("DATABASE_URL")
// Returns value and a boolean indicating presence
apiKey, exists := os.LookupEnv("API_KEY")
if !exists {
fmt.Println("API_KEY is not set")
}
fmt.Println(dbURL, apiKey)
}The distinction between os.Getenv and os.LookupEnv is important: os.Getenvreturns an empty string for both unset variables and variables set to an empty value, while os.LookupEnvlets you distinguish between the two cases.
Setting Environment Variables
Set variables in the shell or use os.Setenv at runtime:
# Shell
export DATABASE_URL=postgres://localhost/mydb
go run main.go
// In Go
os.Setenv("MY_VAR", "value")
os.Unsetenv("MY_VAR")Popular Libraries
envconfig (by kelseyhightower) maps environment variables to a struct using struct tags. It handles type conversion and supports required fields, defaults, and nested structs:
import "github.com/kelseyhightower/envconfig"
type Config struct {
DatabaseURL string `envconfig:"DATABASE_URL" required:"true"`
Port int `envconfig:"PORT" default:"3000"`
Debug bool `envconfig:"DEBUG" default:"false"`
}
var cfg Config
err := envconfig.Process("", &cfg)
if err != nil {
log.Fatal(err)
}godotenv loads .env files in Go. It is a port of the Ruby dotenv gem:
import "github.com/joho/godotenv"
func init() {
godotenv.Load() // loads .env from current directory
}caarlos0/env is another popular option that uses struct tags with a cleaner API and supports more advanced features like file loading and custom parsers.
Common Gotchas
- Go does not have a built-in dotenv loader. You must import a library or set variables externally.
os.Getenvreturns an empty string for unset variables, which can mask configuration errors. Preferos.LookupEnvor a validation library to catch missing variables early.- Environment variable changes made with
os.Setenvare visible to the current process and child processes but are not thread-safe in all Go versions. Read the documentation for your Go version. - When deploying Go binaries in containers, remember that static binaries do not need a shell to set environment variables. The container runtime injects them directly into the process.