What it is
Viper is a configuration library that merges defaults, config files, environment variables, flags and remote key stores into one lookup, with live reloading.
Viper reads JSON, YAML, TOML, HCL and .env files, binds environment variables and Cobra flags, applies defaults, and can watch a file for changes.
Installation
go get github.com/spf13/viperGetting started
The smallest useful thing you can do with it, and what each part means.
viper.SetDefault("port", 8080)
viper.SetDefault("log.level", "info")
viper.SetConfigName("config")
viper.AddConfigPath(".")
viper.AddConfigPath("/etc/myapp/")
// APP_PORT and APP_LOG_LEVEL override the file.
viper.SetEnvPrefix("APP")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
var notFound viper.ConfigFileNotFoundError
if !errors.As(err, ¬Found) {
return err // a malformed file is fatal; a missing one is fine
}
}
port := viper.GetInt("port")type Config struct {
Port int `mapstructure:"port"`
Log struct {
Level string `mapstructure:"level"`
} `mapstructure:"log"`
}
var cfg Config
if err := viper.Unmarshal(&cfg); err != nil {
return err
}Advanced usage
Where the library earns its place over a simpler alternative.
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
var next Config
if err := viper.Unmarshal(&next); err != nil {
log.Printf("ignoring bad config: %v", err)
return // keep running with the old configuration
}
current.Store(&next) // atomic swap, readers see one or the other
})Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Environment variables are ignored
- AutomaticEnv only applies to keys Viper knows about. Register them with SetDefault or BindEnv, and set a key replacer for nested names.
- Unmarshal leaves fields zero
- Viper uses mapstructure tags, not json. Add mapstructure:"name" to each field.
Best practices
- Unmarshal into a typed struct once at startup rather than calling Get throughout the code.
- Use SetEnvKeyReplacer so nested keys map to conventional SCREAMING_SNAKE environment variables.
- Treat a missing config file as acceptable and a malformed one as fatal.
- Validate the resulting struct before using it — Viper checks types, not business rules.
Background
Why it exists, and what it was reacting to.
Also from Steve Francia, Viper was designed as Cobra's companion so a CLI could accept the same setting from a flag, an environment variable or a YAML file without writing the precedence logic each time.
