Skip to main content
  1. Tutorials/

How to use environment variables in Go (get, set, expand)

··3 mins

Environment variables are key-value strings provided by the operating system. They are commonly used to pass configuration into Go programs without hard-coding secrets or settings. In Go, you work with them through the standard os package.

Each variable has a key (like APP_PORT) and a value (like 8080). Environment variables are scoped to the current process and are inherited by child processes, which is why tools like Docker and CI pipelines rely on them.

Read environment variables safely #

Use os.LookupEnv to tell the difference between an empty value and a missing variable. If you only use os.Getenv, a missing variable looks the same as an empty one. You can also build a small helper to provide defaults.

package main

import (
    "fmt"
    "os"
)

func getenvDefault(key, fallback string) string {
    if val, ok := os.LookupEnv(key); ok {
        return val
    }
    return fallback
}

func main() {
    _ = os.Setenv("APP_EMPTY", "")
    _ = os.Setenv("APP_PORT", "8080")

    fmt.Printf("Getenv(APP_EMPTY): %q\n", os.Getenv("APP_EMPTY"))

    val, ok := os.LookupEnv("APP_EMPTY")
    fmt.Printf("LookupEnv(APP_EMPTY): ok=%t value=%q\n", ok, val)

    fmt.Printf("APP_PORT with default: %s\n", getenvDefault("APP_PORT", "3000"))
    fmt.Printf("APP_MISSING with default: %s\n", getenvDefault("APP_MISSING", "3000"))
}

Output:

Getenv(APP_EMPTY): ""
LookupEnv(APP_EMPTY): ok=true value=""
APP_PORT with default: 8080
APP_MISSING with default: 3000

Set and unset variables #

os.Setenv and os.Unsetenv affect only the current process (and its children), not your shell. If you need a variable available in your shell, set it with export or your shell config file.

package main

import (
    "fmt"
    "os"
)

func main() {
    const key = "APP_TOKEN"

    if err := os.Setenv(key, "secret-123"); err != nil {
        panic(err)
    }

    fmt.Printf("After Setenv: %s=%s\n", key, os.Getenv(key))

    if err := os.Unsetenv(key); err != nil {
        panic(err)
    }

    _, ok := os.LookupEnv(key)
    fmt.Printf("After Unsetenv: ok=%t\n", ok)
}

Output:

After Setenv: APP_TOKEN=secret-123
After Unsetenv: ok=false

List variables and clear the environment #

Use os.Environ to list the process environment. os.Clearenv removes everything for the current process. This is handy for short-lived tools and tests.

package main

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

func main() {
    _ = os.Setenv("APP_NAME", "gosamples")
    _ = os.Setenv("APP_ENV", "dev")

    count := 0
    for _, env := range os.Environ() {
        if strings.HasPrefix(env, "APP_") {
            fmt.Println(env)
            count++
        }
    }
    fmt.Printf("APP_ variables: %d\n", count)

    os.Clearenv()
    fmt.Printf("After Clearenv: %d variables\n", len(os.Environ()))
}

Output:

APP_NAME=gosamples
APP_ENV=dev
APP_ variables: 2
After Clearenv: 0 variables

Use os.ExpandEnv for $VAR or ${VAR} expansion, and os.Expand when you want custom handling (for example, a fallback value).

package main

import (
    "fmt"
    "os"
)

func main() {
    _ = os.Setenv("APP_HOME", "/srv/app")
    _ = os.Setenv("USER", "gosamples")

    fmt.Println(os.ExpandEnv("$APP_HOME/logs"))

    expanded := os.Expand("User=${USER}, app=${APP_NAME}", func(key string) string {
        if key == "APP_NAME" {
            return "gosamples"
        }
        return os.Getenv(key)
    })

    fmt.Println(expanded)
}

Output:

/srv/app/logs
User=gosamples, app=gosamples

Common mistakes #

  • ❌ Using os.Getenv to check if a variable exists. ✅ Use os.LookupEnv to detect missing keys.
  • ❌ Expecting os.Setenv to modify your shell environment. ✅ Use export in the shell for that.
  • ❌ Calling os.Clearenv in shared libraries. ✅ Reserve it for tests or short-lived tools.

Best practices #

  • Treat environment variables as immutable configuration once your app starts.
  • Document required variables and defaults in README or sample config.
  • Avoid storing secrets in code; read them from env or a secrets manager.

Tested with Go 1.25+ | Last verified: December 2025 🎉