Go by Example: Configuration with Viper
Manage application configuration effectively with Viper. This example demonstrates how to read configuration from files (JSON, YAML, etc.), set defaults, and access values, providing a robust solution for 12-factor apps.
Code
package main
import (
"fmt"
"github.com/spf13/viper"
)
func main() {
viper.SetConfigFile("config.yaml")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
// Set defaults
viper.SetDefault("port", 8080)
viper.SetDefault("env", "dev")
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
fmt.Println("Config file not found, using defaults")
} else {
panic(fmt.Errorf("fatal error config file: %w", err))
}
}
fmt.Println("Port:", viper.GetInt("port"))
fmt.Println("Env:", viper.GetString("env"))
// Nested configuration
fmt.Println("Database Host:", viper.GetString("database.host"))
}Explanation
Viper is the comprehensive configuration solution for Go, designed to handle the complexity of modern "12-Factor" applications. It unifies configuration from multiple sources, allowing your app to run seamlessly in local, development, and production environments.
Viper resolves configuration keys based on a strict precedence order (highest to lowest):
- Explicit calls:
viper.Set() - Flags: Command-line flags (when bound to Viper)
- Environment: Environment variables (e.g.,
APP_PORT=9090) - Config File: Values from JSON, YAML, TOML, etc.
- Defaults:
viper.SetDefault()
This layering allows you to define sensible defaults, override them with a config file for general settings, and use environment variables or flags for specific deployment overrides.

