# Use Viper for configuration management * Status: Accepted * Deciders: Gabriel Radureau, AI Agent * Date: 2026-04-03 ## Context and Problem Statement We needed a configuration management solution for dance-lessons-coach that provides: - Support for multiple configuration sources (files, environment variables, defaults) - Configuration validation - Type-safe configuration loading - Hot reloading capabilities - Good error handling and reporting ## Decision Drivers * Need for flexible configuration from multiple sources * Desire for configuration validation * Requirement for type-safe access to configuration * Need for environment-specific configurations * Desire for good error messages ## Considered Options * Viper - Popular configuration library with many features * Koanf - Lightweight but powerful * envconfig - Simple environment variable loading * Custom solution - Build our own configuration loader ## Decision Outcome Chosen option: "Viper" because it provides comprehensive configuration management with support for multiple sources, good validation capabilities, type-safe loading, and is widely used in the Go ecosystem. ## Pros and Cons of the Options ### Viper * Good, because supports multiple configuration sources * Good, because good validation capabilities * Good, because type-safe configuration loading * Good, because widely used and well-documented * Good, because supports hot reloading * Bad, because slightly heavier than alternatives * Bad, because more complex API ### Koanf * Good, because lightweight * Good, because good performance * Good, because simple API * Bad, because less feature-rich than Viper * Bad, because smaller community ### envconfig * Good, because very simple * Good, because good for environment variables * Bad, because limited to environment variables * Bad, because no file support ### Custom solution * Good, because tailored to our needs * Good, because no external dependencies * Bad, because time-consuming to develop * Bad, because need to maintain ourselves * Bad, because likely less feature-rich ## Implementation Example ```go // Configuration structure type Config struct { Server ServerConfig `mapstructure:"server"` Shutdown ShutdownConfig `mapstructure:"shutdown"` Logging LoggingConfig `mapstructure:"logging"` } // Loading configuration func LoadConfig() (*Config, error) { v := viper.New() // Set defaults v.SetDefault("server.host", "0.0.0.0") v.SetDefault("server.port", 8080) // Read config file v.SetConfigName("config") v.SetConfigType("yaml") v.AddConfigPath(".") if err := v.ReadInConfig(); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); !ok { return nil, err } } // Bind environment variables v.AutomaticEnv() v.SetEnvPrefix("DLC") // Unmarshal into struct var config Config if err := v.Unmarshal(&config); err != nil { return nil, err } return &config, nil } ``` ## Configuration Priority The implementation follows this priority order: 1. **Config file** (highest priority) 2. **Environment variables** (override defaults) 3. **Default values** (lowest priority) ## Links * [Viper GitHub](https://github.com/spf13/viper) * [Viper Documentation](https://github.com/spf13/viper#readme) * [Koanf GitHub](https://github.com/knadh/koanf) * [envconfig GitHub](https://github.com/kelseyhightower/envconfig) ## Configuration File Example ```yaml # config.yaml server: host: "0.0.0.0" port: 8080 shutdown: timeout: 30s logging: json: false level: "trace" ``` ## Environment Variables ```bash # Set configuration via environment variables export DLC_SERVER_HOST="0.0.0.0" export DLC_SERVER_PORT=8080 export DLC_SHUTDOWN_TIMEOUT=30s export DLC_LOGGING_JSON=false ```