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

# In terminal
go get github.com/spf13/viper

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:

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

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:

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

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

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"`
}

2.4.2 custom.go

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"`
}

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.

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)

2.5 Key step: struct mapping logic

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

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 
", 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)
}

2.6 Overall file structure

Project structure
Project structure

2.7 Running the program

main.go loads the configuration and prints it:

package main

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

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

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

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

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.