Setting Environment Variables for a Project - VIPER

Written byKalanKalan
💡

If you have any questions or feedback, pleasefill out this form

This post is translated by ChatGPT and originally written in Mandarin, so there may be some inaccuracies or mistakes.

Several months ago, I wrote an article on how to set environment variables in Golang. Elegantly configuring environment variables is quite important, so I created a simple function to handle this task.

The initial idea was straightforward: if a corresponding config file is provided, the key/value pairs within it can be set using os.Setenv. This way, throughout the entire app, we can directly retrieve values using os.Getenv.

However, once it comes time for a formal deployment, several issues inevitably arise:

  • The configuration file may not necessarily be in YAML format; it could be in other formats as well.
  • Sometimes, we may want to inject environment variables through external services (like Consul, etcd, etc.), but the current method relies on os.Getenv.
  • Configuration files can be read from different paths.
  • Variables can be set through the command line.
  • There are many more unexpected problems.

In smaller projects, this approach may resolve my issues, but when more flexible configuration methods are needed, this alone is insufficient.

Fortunately, Golang already has a mature solution for these problems called Viper.

VIPER

Viper is a powerful library for environment variable configuration. It supports the following features:

  • Default values
  • Support for different formats of configuration files (json, toml, yaml)
  • Ability to watch for changes in configuration files (no need to restart the server!)
  • Capability to fetch variables from remote servers (like Consul or etcd)
  • Use of flag to retrieve variables
  • Ability to read variables from a reader, allowing for variable configuration from different sources.

Basic Usage

First, download Viper using go get or go mod.

go get github.com/spf13/viper

func main() {
  viper.SetDefault("AWS_ACCESS_TOKEN", "AWS123456789") // Set default value
	viper.SetConfigName("config") // Specify the config file name
	viper.AddConfigPath("./config")
	viper.ReadInConfig()
	viper.AutomaticEnv()
}
  • SetDefault(key, value): Set default value.
  • SetConfigName(name): Set the config file name; for example, if our config file is called config.yml, we simply use config. Why not specify the type? Viper handles that for us automatically.
  • AddConfigPath: Allows specifying multiple directories.
  • ReadInConfig: Remember to call this to actually read the configuration.
  • AutomaticEnv: Automatically syncs environment variables into Viper.

Viper also provides many functions for convenient configuration.

Retrieving Variables

After setting variables, we can read them using viper.Get. The Get function returns an interface{}, but Viper also provides numerous type conversion functions, such as viper.GetString, viper.GetDuration, and viper.GetStringMap.

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

Conclusion

Setting variables is not as simple as it seems; there are more considerations than one might think, and Viper helps us handle many common use cases.

Additionally, it’s crucial to remember to include sensitive information, like access tokens or secret keys, in .gitignore to prevent accidental commits to GitHub, which could lead to unfortunate consequences.

If you found this article helpful, please consider buying me a coffee ☕ It'll make my ordinary day shine ✨

Buy me a coffee