Skip to content

The Secrets to Easy Golang Application Configuration with Viper

Building flexible applications requires us to separate configuration from code. This allows us to easily adapt the application to different environments, such as local computers, production servers, or even user devices. That way, configurations such as database connection details can be changed without having to modify the application's core code.

Separating configuration from code has several advantages. First, we can change the configuration without having to redeploy the entire application. Second, it improves application security because sensitive information, such as database passwords, is no longer exposed in the code. Finally, the application becomes easier to maintain and develop. Viper is one of the popular Golang libraries for configuration management, supporting many types of configuration files, such as JSON, YAML, env files, properties, and others.

Project Initialization

The first step is to create a project first, then install the viper package.

mkdir learn-viper && cd learn-viper

then init go modules

go mod init learn-viper

install viper

go get github.com/spf13/viper

Setting Application Configuration

Here we will only give examples of popular configuration files such as JSON files, YAML files, and env files.

Create new file config.json and the following code

{
  "app": {
    "name": "golang-viper",
    "env": "development"
  },
  "database": {
    "host": "localhost",
    "port": 5432,
		"user": "postgres",
		"pass": "secrete123",
		"name": "my_db",
    "show_sql": true
  }
}

Create New File config.yaml and the following code

app:
  name: "golang-viper"
  env: "development"

database:
  host: "localhost"
  port: 5432
	user: "postgres"
	pass: "secrete123"
	name: "my_db"
  show_sql: true

create new file local.env and the following code

APP_NAME=golang-viper
APP_ENV=development

DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASS=secrete123
DB_NAME=my_db
DB_SHOW_SQL=true

Use Viper and test your configuration

install package testing

go get github.com/stretchr/testify

create new file config_test.go and the following code

package learn_viper

import (
	"testing"

	"github.com/spf13/viper"
	"github.com/stretchr/testify/assert"
)

func TestViper(t *testing.T) {
	var config *viper.Viper = viper.New()
	assert.NotNil(t, config)
}

func TestJSON(t *testing.T) {
	config := viper.New()
	config.SetConfigName("config")
	config.SetConfigType("json")
	config.AddConfigPath(".")

	// read config
	err := config.ReadInConfig()
	assert.Nil(t, err)

	assert.Equal(t, "golang-viper", config.GetString("app.name"))
	assert.Equal(t, "development", config.GetString("app.env"))
	assert.Equal(t, "localhost", config.GetString("database.host"))
	assert.Equal(t, 5432, config.GetInt("database.port"))
	assert.Equal(t, "postgres", config.GetString("database.user"))
	assert.Equal(t, "secrete123", config.GetString("database.pass"))
	assert.Equal(t, "my_db", config.GetString("database.name"))
	assert.Equal(t, true, config.GetBool("database.show_sql"))
}

func TestYAML(t *testing.T) {
	config := viper.New()
	config.SetConfigName("config")
	config.SetConfigType("yaml")
	config.AddConfigPath(".")

	// read config
	err := config.ReadInConfig()
	assert.Nil(t, err)

	assert.Equal(t, "golang-viper", config.GetString("app.name"))
	assert.Equal(t, "development", config.GetString("app.env"))
	assert.Equal(t, "localhost", config.GetString("database.host"))
	assert.Equal(t, 5432, config.GetInt("database.port"))
	assert.Equal(t, "postgres", config.GetString("database.user"))
	assert.Equal(t, "secrete123", config.GetString("database.pass"))
	assert.Equal(t, "my_db", config.GetString("database.name"))
	assert.Equal(t, true, config.GetBool("database.show_sql"))
}

func TestENVFile(t *testing.T) {
	config := viper.New()
	config.SetConfigName("local")
	config.SetConfigType("env")
	// config.AutomaticEnv() // if env not file
	config.AddConfigPath(".")

	// read config
	err := config.ReadInConfig()
	assert.Nil(t, err)

	assert.Equal(t, "golang-viper", config.GetString("APP_NAME"))
	assert.Equal(t, "development", config.GetString("APP_env"))
	assert.Equal(t, "localhost", config.GetString("DB_HOST"))
	assert.Equal(t, 5432, config.GetInt("DB_PORT"))
	assert.Equal(t, "postgres", config.GetString("DB_USER"))
	assert.Equal(t, "secrete123", config.GetString("DB_PASS"))
	assert.Equal(t, "my_db", config.GetString("DB_NAME"))
	assert.Equal(t, true, config.GetBool("DB_SHOW_SQL"))
}

Running go test ./... -v will run all the test cases in the package.

Output of config_test.go

Conclusion

In conclusion, using the Viper package in Go is very useful for managing configuration applications. It supports multiple configuration file formats, including JSON, YAML, and env files. Viper makes it easy to manage and read configuration files of different types. We can also use Viper to read environment variables and command-line flags.

Viper provides a simple and convenient way to read and write configuration values in our application. It also provides a convenient way to override configuration values with environment variables, command line flags, or remote configuration sources.

In summary, Viper is a powerful tool for managing application configuration in Go. It's easy to use, flexible, and provides a lot of features for managing configuration values.

Reference