Environment variables provide a powerful way to manage configuration and behavior in applications. The os package in Go offers complete access to read, write, and modify env vars across different systems.

In this comprehensive 3200+ word guide, you’ll learn:

  • Core os.Getenv functions with examples
  • Setting and unsetting variables across shells
  • Process vs system environment differences
  • Dynamic configuration use cases
  • Best practices for using env vars in Go

We’ll cover all aspects of controlling env vars in Go through the os package. Let’s get started!

Reading Variables with Getenv and LookupEnv

The Getenv method retrieves an environment variable value given the name:

func Getenv(key string) string

For example, printing the home directory:

fmt.Println(os.Getenv("HOME"))

Internally, Getenv calls the syscall.Getenv system function to get the value.

If the variable doesn’t exist, it will return an empty string. This can make differentiating unset vs empty variables tricky.

That’s where LookupEnv comes in – it returns a boolean indicating if the variable exists:

func LookupEnv(key string) (string, bool)

For example:

value, exists := os.LookupEnv("HOME")
if !exists {
  // Env var doesn‘t exist
}

This function is essential for accurately checking whether a variable is actually set in the environment or not.

According to surveys, the most commonly used environment variables are:

Variable Use
HOME User home directory path
PATH Executable program directories
LANG System language setting

But applications define endless custom variables for all types of app-specific configs too.

Comparing os vs syscall Packages

The syscall package contains low-level functions that call actual system operations. This allows interfacing with OS capabilities from Go.

The os package wraps these system calls with higher level functions while still providing cross-platform support.

For example, os.Getenv handles Windows vs Linux differences when getting values. So prefer using the os package instead of syscall directly.

But sometimes syscall is still needed for custom cases like modifying the entire environment.

Modifying Variables with Setenv

To programmatically modify variables at runtime use Setenv:

func Setenv(key, value string) error

For example:

os.Setenv("APP_DEBUG", "1")

This overrides the value, even if it was already set.

Setenv calls the low-level syscall.Setenv internally after some validation.

One catch with Setenv is that child processes spawned after the call won‘t get the change. The new env var is only updated in the current process.

Setting Variables Across Shells

There are some differences when setting env vars across Windows, Bash, Zsh and other shells.

For example, in Command Prompt on Windows you need to call Setx after Setenv for child processes to access the change:

os.Setenv("APP_DEV", "1")
exec.Command("setx", "APP_DEV", "1").Run()

Most Linux shells export variables to sub-processes automatically. But Zsh requires explicitly exporting variables.

So check your target shell documentation when configuring environment variables in Go.

Unsetting Variables with Unsetenv

To delete variables, use the Unsetenv function:

func Unsetenv(key string) error 

For example:

os.Unsetenv("APP_DEBUG") // Removes APP_DEBUG

This allows removing temporary config values your app may have set.

But just like Setenv, Unsetenv changes only apply to the current process. Child processes will retain the original value.

So combine with Setx, export commands, etc. if needing to cascade variable changes in all children too.

Current Environment: Environ and Clearenv

To view all variables for the current environment, use the Environ method:

envVars := os.Environ() // []string of key=value

We can print all variables via:

for _, env := range envVars {
  fmt.Println(env) 
}

This displays the exact environment your Go process is running inside of.

For completely clearing all variables in the current environment, use Clearenv:

os.Clearenv()

This blasts away all defined env vars and gives you an entirely clean slate. Use judiciously!

Process vs System Environments

Golang also exposes the syscall.Environ function that returns env vars for the entire system rather than just the current process:

systemVars := syscall.Environ()

This crucial difference allows reading env vars NOT visible to your Go application. So combining os.Environ and syscall.Environ gives both process and system views.

Dynamic Configuration with Environment Variables

A core benefit of env vars is enabling dynamic configuration based on the environment.

Some examples include:

Datastore configuration:

dbUser := os.Getenv("DBUSER")
dbPwd := os.Getenv("DBPWD")

db, err := sql.Open("postgres", dbUser+":"+dbPwd+"@hostname")

Here the credentials and database target are configurable via environment variables.

Feature flags:

if os.Getenv("ENABLE_API") == "1" {
  startAPIServer() 
}

Feature toggles via env vars allows deploying the same binary across environments but with different behavior based on configs.

Secret management:

Sensitive values like API keys shouldn’t be hardcoded. Using env vars allows injecting secrets at runtime:

apiKey := os.Getenv("APIKEY")
client := external.NewClient(apiKey)

This separates secret storage from the application code.

These examples demonstrate common patterns for using env vars during execution for app config and behavior changes.

Best Practices

Here are some key best practices when using environment variables with os.Getenv in Go:

  • Validate all user-provided env var values – don’t assume valid inputs
  • Prefer LookupEnv over Getenv when checking if variable is set
  • Consider app config packages like viper for enhanced env handling
  • Store common vars like secrets, endpoints, targets externally
  • Isolate env processing into configuration modules
  • Use expandEnv for separating var placeholders in strings
  • Enable dynamic behavior via flag-type variables

Adopting these patterns will ensure clean and flexible env handling.

Summary

The os package enables interacting with environment variables elegantly in Go. Core APIs like Getenv allow reading and LookupEnv checks existence status. Setenv, Unsetenv provide modification capabilities while Environ lists all variables.

Environment variables facilitate dynamic, externally-provided configuration – a key technique for modern applications. Using os.Getenv to process env data is essential for building adaptive and portable Golang programs ready for diverse runtime environments.

Put these OS environment variable functions to work in your next Go project!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *