Go configuration with fangs - A complete configuration solution for Go applications
npx @tessl/cli install tessl/go-viper@1.21.0Viper is a complete configuration solution for Go applications including 12-Factor apps. It handles all types of configuration needs and formats, providing a prioritized configuration registry that manages multiple configuration sources.
go get github.com/spf13/vipergithub.com/spf13/viperimport "github.com/spf13/viper"For remote configuration features:
import _ "github.com/spf13/viper/remote"package main
import (
"fmt"
"github.com/spf13/viper"
)
func main() {
// Set defaults
viper.SetDefault("port", 8080)
viper.SetDefault("host", "localhost")
// Read from config file
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
panic(err)
}
}
// Read from environment
viper.AutomaticEnv()
// Get values
port := viper.GetInt("port")
host := viper.GetString("host")
fmt.Printf("Server: %s:%d\n", host, port)
}Viper uses the following precedence order (highest to lowest priority):
Set()Important: Viper configuration keys are case-insensitive.
type Viper struct {
// Has unexported fields
}The main configuration management type. Maintains a set of configuration sources and provides values according to priority order.
Note: Viper instances are NOT safe for concurrent Get() and Set() operations.
Constructor Functions:
func New() *Viper
func NewWithOptions(opts ...Option) *Viper
func GetViper() *ViperNew() - Creates a new independent Viper instanceNewWithOptions(opts) - Creates a new Viper instance with configuration optionsGetViper() - Returns the global Viper instanceViper provides both package-level functions (operating on a global instance) and methods on *Viper instances. For example:
// Using global instance
viper.Set("key", "value")
value := viper.GetString("key")
// Using custom instance
v := viper.New()
v.Set("key", "value")
value := v.GetString("key")var SupportedExts = []string{
"json", "toml", "yaml", "yml",
"properties", "props", "prop",
"hcl", "tfvars", "dotenv", "env", "ini"
}Viper supports JSON, TOML, YAML, HCL, INI, dotenv, envfile, and Java properties files.
var SupportedRemoteProviders = []string{
"etcd", "etcd3", "consul", "firestore", "nats"
}Read, write, watch, and merge configuration files in multiple formats.
func AddConfigPath(in string)
func SetConfigFile(in string)
func SetConfigName(in string)
func SetConfigType(in string)
func ReadInConfig() error
func WriteConfig() error
func SafeWriteConfig() errorKey Functions:
AddConfigPath - Adds search paths for config filesSetConfigFile - Sets explicit config file pathSetConfigName - Sets config file name (without extension)SetConfigType - Sets config file type (json, yaml, etc.)ReadInConfig - Discovers and loads config fileWriteConfig - Writes current config to fileSafeWriteConfig - Writes only if file doesn't existSet defaults, override values, and retrieve configuration values with type-safe getters.
func SetDefault(key string, value any)
func Set(key string, value any)
func Get(key string) any
func GetString(key string) string
func GetInt(key string) int
func GetBool(key string) boolKey Functions:
SetDefault - Sets default value for a keySet - Sets override value (highest priority)Get - Retrieves any valueGetString, GetInt, GetBool, etc. - Type-safe gettersAllKeys - Returns all keysAllSettings - Returns all settings as mapBind environment variables and command-line flags to configuration keys.
func AutomaticEnv()
func BindEnv(input ...string) error
func SetEnvPrefix(in string)
func BindPFlag(key string, flag *pflag.Flag) errorKey Functions:
AutomaticEnv - Automatically check env vars for all keysBindEnv - Bind specific env var to keySetEnvPrefix - Set prefix for env var namesBindPFlag - Bind pflag to keyBindPFlags - Bind entire FlagSetEnvironment Variables and Flags
Read configuration from remote key/value stores like etcd, Consul, Firestore, and NATS.
func AddRemoteProvider(provider, endpoint, path string) error
func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error
func ReadRemoteConfig() error
func WatchRemoteConfig() errorNote: Requires importing the remote package: import _ "github.com/spf13/viper/remote"
Options for customization, codec registration, unmarshaling to structs, and more.
type Option interface {
// Has unexported methods
}
func KeyDelimiter(d string) Option
func WithLogger(l *slog.Logger) Option
func WithFinder(f Finder) Option
func WithEncoderRegistry(r EncoderRegistry) Option
func WithDecoderRegistry(r DecoderRegistry) Option
func Unmarshal(rawVal any, opts ...DecoderConfigOption) error
func UnmarshalKey(key string, rawVal any, opts ...DecoderConfigOption) errorKey Features:
type ConfigFileNotFoundError struct {
// Has unexported fields
}
type ConfigParseError struct {
// Has unexported fields
}
type UnsupportedConfigError string
type RemoteConfigError stringviper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("/etc/myapp/")
viper.AddConfigPath("$HOME/.myapp")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Config file not found; use defaults
} else {
// Config file found but error occurred
panic(err)
}
}// 1. Set defaults
viper.SetDefault("port", 8080)
viper.SetDefault("log_level", "info")
// 2. Read config file
viper.SetConfigName("config")
viper.AddConfigPath(".")
viper.ReadInConfig()
// 3. Bind environment variables
viper.SetEnvPrefix("MYAPP")
viper.AutomaticEnv()
// 4. Bind flags
viper.BindPFlag("port", cmd.Flags().Lookup("port"))
// Values retrieved with precedence: flags > env > config > defaults
port := viper.GetInt("port")viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
})
viper.WatchConfig()type Config struct {
Port int `mapstructure:"port"`
Host string `mapstructure:"host"`
LogLevel string `mapstructure:"log_level"`
}
var config Config
err := viper.Unmarshal(&config)Viper instances are NOT safe for concurrent Get() and Set() operations. If you need concurrent access, use appropriate synchronization mechanisms or separate Viper instances per goroutine.