Backend Development 9 min read

Master Go Configuration with Viper: A Step-by-Step Guide

This guide walks through installing Viper, creating common and environment‑specific YAML configuration files, mapping them to Go structs, setting up a global configuration holder, and initializing the config with live watching, providing a complete, runnable example for Go backend projects.

Architecture & Thinking
Architecture & Thinking
Architecture & Thinking
Master Go Configuration with Viper: A Step-by-Step Guide

1 Introduction

Viper (https://github.com/spf13/viper) is a complete configuration solution for Go applications, designed to work inside applications and handle all types of configuration needs and formats. It currently has 26.6k stars and supports features such as:

Setting default values

Reading configuration from JSON, TOML, YAML, HCL, envfile and Java properties files

Live watching and re-reading configuration files (optional)

Reading from environment variables

Reading from remote configuration systems (etcd or Consul) and monitoring changes

Reading from command‑line arguments

Reading from a buffer

Explicitly setting configuration values

2 Using Viper in a Golang Project

2.1 Installing Viper

<code># In terminal
go get github.com/spf13/viper
</code>

2.2 Writing a common configuration file

Because Viper supports multiple file formats, we use a YAML example. Create a conf folder with a files sub‑folder and add a config.yaml file containing basic configuration:

<code>app:
  env: local
  port: 8888
  app_name: traffic-demo
  app_url: http://localhost

MySQL:
  host: 127.0.0.1
  port: 3306
  user: root
  password: <PASSWORD>
  db_name: traffic
</code>

This defines two configuration sections: app and MySQL .

2.3 Writing environment‑specific custom configuration files

Place four folders ( local , dev , beta , prod ) under config/files/ , each containing a custom.yaml . The file loaded depends on the value of app.env . Example local/custom.yaml :

<code>white_list:
  user_id: # User ID list
    - 063105015
    - 063105024
    - 063105028
  request_path: # Access paths
    - /api/v1/users
    - /api/v1/ops
</code>

2.4 Mapping configuration to structs

Create a conf/model folder with config.go and custom.go to define Go structs that map the configuration.

2.4.1 config.go

<code>package config

// Configuration aggregates the config sections
type Configuration struct {
    App   App   `mapstructure:"app" json:"app" yaml:"app"`
    MYSQL MYSQL `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
}

// App configuration
type App struct {
    Env     string `mapstructure:"env" json:"env" yaml:"env"`
    Port    string `mapstructure:"port" json:"port" yaml:"port"`
    AppName string `mapstructure:"app_name" json:"app_name" yaml:"app_name"`
    AppUrl  string `mapstructure:"app_url" json:"app_url" yaml:"app_url"`
}

// MySQL configuration
type MYSQL struct {
    Host     string `mapstructure:"host" json:"host" yaml:"host"`
    Port     string `mapstructure:"port" json:"port" yaml:"port"`
    User     string `mapstructure:"user" json:"user" yaml:"user"`
    Password string `mapstructure:"password" json:"password" yaml:"password"`
    DbName   string `mapstructure:"db_name" json:"db_name" yaml:"db_name"`
}
</code>

2.4.2 custom.go

<code>package config

type Custom struct {
    WhiteList WhiteList `mapstructure:"white_list" json:"white_list" yaml:"white_list"`
}

type WhiteList struct {
    UserId      []string `mapstructure:"user_id" json:"user_id" yaml:"user_id"`
    RequestPath []string `mapstructure:"request_path" json:"request_path" yaml:"request_path"`
}
</code>

2.5 Creating a global variable for configuration

Define a global/app.go file with an Application struct that holds the Viper instance, the parsed Configuration , and the custom configuration.

<code>package global

import (
    "github.com/spf13/viper"
    config "traffic.demo/config/model"
)

type Application struct {
    ConfigViper *viper.Viper
    Config      config.Configuration
    Custom      config.Custom
}

// Global instance
var App = new(Application)
</code>

2.5 Key step: struct mapping logic

The core parsing logic resides in bootstrap/config.go :

<code>package bootstrap

import (
    "fmt"
    "github.com/fsnotify/fsnotify"
    "github.com/spf13/viper"
    "traffic.demo/global"
)

// Generic function to assemble configuration and return a *viper.Viper
func configAssemble[T any](configPath string, viperStruct T) *viper.Viper {
    v := viper.New()
    v.SetConfigFile(configPath)
    v.SetConfigType("yaml")
    if err := v.ReadInConfig(); err != nil {
        panic(fmt.Errorf("read config failed: %s \n", err))
    }
    v.WatchConfig()
    v.OnConfigChange(func(in fsnotify.Event) {
        fmt.Println("config file changed:", in.Name)
        if err := v.Unmarshal(viperStruct); err != nil {
            fmt.Println(err)
        }
    })
    if err := v.Unmarshal(viperStruct); err != nil {
        fmt.Println(err)
    }
    return v
}

// InitializeConfig loads the main and environment‑specific configs
func InitializeConfig() {
    config := "conf/files/config.yaml"
    configAssemble(config, &global.App.Config)

    customConfig := fmt.Sprintf("%s%s%s", "conf/files/", global.App.Config.App.Env, "/custom.yaml")
    configAssemble(customConfig, &global.App.Custom)
}
</code>

2.6 Overall file structure

2.7 Running the program

main.go loads the configuration and prints it:

<code>package main

import (
    "fmt"
    "traffic.demo/global"
)

func main() {
    bootstrap.InitializeConfig()
    fmt.Println("Traffic Service Started...!")
    fmt.Printf("globalCong: %+v\n", global.App.Config)
    fmt.Printf("customCong: %+v\n", global.App.Custom)
}
</code>

Execution output shows the loaded configuration (screenshot omitted).

3 Summary

Viper is a powerful, simple, and easy‑to‑use Go configuration library that helps developers manage application settings flexibly.

BackendconfigurationGotutorialViperStruct Mapping
Architecture & Thinking
Written by

Architecture & Thinking

🍭 Frontline tech director and chief architect at top-tier companies 🥝 Years of deep experience in internet, e‑commerce, social, and finance sectors 🌾 Committed to publishing high‑quality articles covering core technologies of leading internet firms, application architecture, and AI breakthroughs.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.