Go has many packages that can handle configurations for your applications. But Viper is one of the most popular and complete configuration solutions that helps you configure your application easily.
Viper makes your app compliant with the Twelve-Factor-App checklist, which is a method for building SaaS applications. First drafted by Heroku, this checklist helps make your apps more portable and resilient by using declarative formats to set up automation.
This helps new developers in the codebase get started easily and quickly, and it also minimizes the difference between production and development — all of which helps in continuous deployment.
Viper currently supports:
.env
files, and Java properties config filesSet
.env
filesIdeally, Viper enables us to spend less time configuring the application and more time actually building our app. Viper achieves this by ensuring we can set up our configuration easily.
There are many cases when we need to set up defaults for the application or load config variables from different file types, and this is where using Viper can be extremely useful. It can even live-read config variables, work with flags, and enable you to marshal and unmarshal.
The use cases for Viper are enormous, and building applications with Go becomes more manageable when used with Viper. In this article, you’ll learn how to use Viper and apply it to these use cases.
Installing Viper is similar to installing any package in Go. The first step is to initialize the Go mod file. The best way to do this is to initialize the folder with git init
.
Next, set up the git origin using git remote add origin ORIGIN_URL
, then initialize the project with go mod init
. It’ll create a go.mod
file.
The go.mod
file is all you need to install any packages to your project. To install Viper, run the following command in your terminal:
go get github.com/spf13/viper
.env
filesLet’s load environment variables from a .env
file. Create the .env
file in your project’s root directory and define your environment variables there. For example, let’s say you have three variables that store the database address, port, and an API secret. The file will look similar to the file shown below:
PORT=3000 MONGO_URI=mongodb+srv://nemo0:[email protected]/myFirstDatabase?retryWrites=true&w=majority API_SECRET=Y1VFGSea2EPa6v3gFY84swUJbZCHY8WEzKfdq6uPUyRjYR
To use these .env
variables in your main.go
file, you’ll have to let Viper know the path and file name of your .env
file. If your Go file and the .env
file are at the exact location, you can initialize the .env
file with Viper using this:
viper.SetConfigFile(".env")
To read the .env
file, you have to add the following code:
viper.ReadInConfig()
Once you add the above line after setting the config file, you can read the environment values with viper.Get("KEY")
, where KEY
is the variable name. For example, viper.Get("PORT")
will read the PORT
from the .env
file.
The complete code for the above example will look like this:
package main import ( "fmt" "github.com/spf13/viper" ) func main() { viper.SetConfigFile(".env") viper.ReadInConfig() fmt.Println(viper.Get("PORT")) }
Running this code will output 3000
in the console.
But, as we know, Viper is not limited only to .env
files only. Let’s take our app one step further and read the configuration from a JSON file.
Let’s say you have a config.json
file inside a configs
folder in your project root directory. To read data from this file, you can write:
viper.AddConfigPath("./configs") viper.SetConfigName("config") // Register config file name (no extension) viper.SetConfigType("json") // Look for specific type viper.ReadInConfig() port := viper.Get("prod.port") fmt.Println(port)
The viper.AddConfigPath("./configs")
line sets the config file path. You can specify multiple paths by adding multiple AddConfigPath
methods, and Viper will read them in the order you provide.
viper.SetConfigName("config")
registers the configuration file. In most cases, you don’t add the extension here. viper.SetConfigType("json")
will tell Viper to read-only from JSON files, and it is an optional field. Finally, after adding viper.ReadInConfig()
, you are ready to read from the configuration file.
If you have a configuration JSON file like below, you can read the port
variable using viper.Get("prod.port")
, as seen in the above code example.
{ "prod": { "port": "3000" } }
WatchConfig()
in ViperViper gives you the ability to live-read the changes from your config file via the WatchConfig()
method. Here’s a simple example of this implemented with the fsnotify package, a cross-platform system notifications package.
viper.WatchConfig() viper.OnConfigChange(func(e fsnotify.Event) { fmt.Println("Config file changed:", e.Name) })
The WatchConfig()
method will look for changes in the config file, while the onConfigChange
is an optional method that will run each time the file changes.
There may be cases when you don’t want to type sensitive information repeatedly in the CLI. Viper can help! You can save the sensitive information in your .env
or any other config file, read it from there, and pass it to the CLI.
There’s a package called Cobra that enables us to create powerful CLI applications and helps us set flag values.
Here’s an example:
package main import ( "fmt" "github.com/spf13/cobra" "github.com/spf13/viper" ) func main() { command := &cobra.Command{ Run: func(c *cobra.Command, args []string) { fmt.Println(viper.GetString("Flag")) }, } viper.SetDefault("Flag", "Flag Value") command.Execute() }
Here, we use two packages apart from using fmt
. The first package is cobra
, which creates a CLI command, and the second package, viper
, sets the default value.
The command
variable in the above example holds a fundamental function that runs on the CLI and prints the flag value. A default value for the flag is set using viper.SetDefault("Flag", "Flag Value")
.
We run the CLI app using the command.Execute()
method. Running this file will output Flag Value
in the terminal because it is set as the default value for the flag. You can also read from separate config files and bind the values to a flag.
Viper can help you with marshaling and unmarshaling values. Marshaling is the process of converting a string into JSON, and unmarshaling is the opposite. Viper gives two methods, Marshal
and Unmarshal
, to accomplish the tasks.
In this article, we’ve discussed the use cases of using Viper with Go. You’ve learned how to install and set up Viper, and we covered common use cases, such as loading environment variables from different file types. We’ve also covered how to use the WatchConfig
method and use flags in Go.
Viper has many more use cases than what I’ve mentioned in this article. You can visit the GitHub repo to get an idea of all the features Viper provides. Using Viper can help you set up your application in a more robust way.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.