process.env.dev

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:

go
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:

go
# 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:

go
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:

go
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.Getenv returns an empty string for unset variables, which can mask configuration errors. Prefer os.LookupEnv or a validation library to catch missing variables early.
  • Environment variable changes made with os.Setenv are 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.