· 3 min read

Setting Up Environment Variables for Your Project - VIPER

This article was auto-translated from Chinese. Some nuances may be lost in translation.

A few months ago, I wrote an article about how to configure environment variables in Go. Elegantly setting up environment variables is quite important, so I wrote a simple function to handle it.

The initial rationale was straightforward: if a corresponding config file was provided, its key/value pairs would be set using os.Setenv. After that, throughout the entire app, you could directly use os.Getenv to retrieve values.

However, once it came time for actual deployment, a few inevitable problems surfaced:

  • The configuration file isn’t necessarily YAML; it could be in other formats.
  • Sometimes you want to inject environment variables via external services (consul, etcd, etc.), but the current approach relied on os.Getenv.
  • The need to read configuration files from different paths.
  • The need to set variables via the command line.
  • Even more unexpected issues.

In small projects, this approach did solve my problem. But once you need more flexible configuration options, that alone isn’t enough.

Fortunately, there is already a mature solution for these problems in the Go ecosystem called Viper.

VIPER

VIPER is a powerful configuration management library for environment variables and configuration files. It supports the following features:

  • Default values
  • Support for various configuration file formats (json, toml, yaml)
  • Watching configuration file changes (no need to restart the server!)
  • Reading variables from remote servers (such as consul or etcd)
  • Reading variables using flags
  • Reading variables from a reader, which means you can configure variables from various sources

Basic Usage

First, download VIPER using go get or Go modules:

go get github.com/spf13/viper

func main() {
  viper.SetDefault("AWS_ACCESS_TOKEN", "AWS123456789") // Set default value
	viper.SetConfigName("config") // Specify config file name
	viper.AddConfigPath("./config")
	viper.ReadInConfig()
	viper.AutomaticEnv()
}
  • SetDefault(key, value): Sets a default value.
  • SetConfigName(name): Sets the config file name. For example, if our configuration file is named config.yml, we specify config. Why don’t we need to specify the file extension? Viper handles that automatically.
  • AddConfigPath: Allows you to specify multiple directories to search.
  • ReadInConfig: Make sure to call this to actually load and parse the configuration.
  • AutomaticEnv: Automatically synchronizes ENV variables into Viper.

Viper also provides many other functions to make configuration easy.

Accessing Variables

After configuring your variables, you can read them using viper.Get. Get returns an interface{}, but Viper also provides many type casting methods, such as viper.GetString, viper.GetDuration, viper.GetStringMap, and more.

func main() {
	fmt.Println(viper.GetString("AWS_ACCESS_TOKEN"))
  fmt.Println(viper.GetUint32("YOUR_INT"))
  fmt.Println(viper.GetTime("YOUR_TIME"))
}

Summary

Configuring variables may seem simple at first glance, but there is more to consider than you might expect. VIPER takes care of many common use cases for us.

One final reminder: when configuring sensitive information like access tokens or secret keys, always make sure to add them to .gitignore to avoid accidentally pushing them to GitHub and causing regret.

Related Posts

Explore Other Topics