Setting Up Environment Variables for Your Project - VIPER
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
consuloretcd) - 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 namedconfig.yml, we specifyconfig. 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 synchronizesENVvariables 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
- When a Measure Becomes a Target: From the Window Tax to Pull Request Counts I once wrote a script to tally how many PRs I contributed in a quarter, how many reviews I left, and how many tickets I closed, hoping to use numbers to prove my output to my manager. My manager simply remarked that performance isn't just about output. Years later, I finally understood—when a measure becomes a target, it ceases to be a good measure. From the British window tax and the Hanoi rat bounty to evaluating developers by PR counts today, the underlying mechanism is exactly the same.
- Using Cloudflare Images for Image Storage and Transformation Putting an image on a webpage is the simplest task in frontend development. But doing it properly—including resizing, generating multiple formats, and withstanding heavy traffic—is actually an entire end-to-end solution. Eventually, I offloaded everything to Cloudflare Images, keeping only a single original image.
- Stop Using AWS Access Keys Access Keys are an easily overlooked security risk in AWS. By pairing OIDC with IAM Roles, GitHub Actions can securely operate AWS resources without storing any secrets.
- Database Primary Keys: AUTO_INCREMENT, UUID, and UUIDv7 Backend developers often face the choice of primary keys: should you use auto-increment or UUID? What about collisions? How does UUIDv7 compare to created_at + index in performance? Here are the design decisions and benchmark results from testing 20 million rows.