Configuración con viper y envconfig
Los servicios y las CLIs necesitan una configuración que cambie por entorno sin recompilar.
Busca en todas las páginas de la documentación
Los servicios y las CLIs necesitan una configuración que cambie por entorno sin recompilar.
spf13/viper fusiona archivos, flags y variables de entorno con reglas de precedencia; kelseyhightower/envconfig mapea variables de entorno directamente a structs tipados para binarios más pequeños.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AutomaticEnv()
viper.SetDefault("http.port", 8080)
_ = viper.ReadInConfig()
port := viper.GetInt("http.port")type Config struct {
Port int `envconfig:"PORT" default:"8080"`
DSN string `envconfig:"DATABASE_URL" required:"true"`
}
var cfg Config
envconfig.Process("", &cfg)Cuándo usar esto:
os.Getenv ad hoc disperso por los paquetespackage main
import (
"fmt"
"log"
"strings"
"github.com/spf13/viper"
)
type AppConfig struct {
HTTPPort int
LogLevel string
DSN string
}
func loadViper() AppConfig {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
viper.SetDefault("http.port", 8080)
viper.SetDefault("log.level", "info")
if err := viper.ReadInConfig(); err != nil {
log.Printf("no config file: %v", err)
}
return AppConfig{
HTTPPort: viper.GetInt("http.port"),
LogLevel: viper.GetString("log.level"),
DSN: viper.GetString("database.dsn"),
}
}
func main() {
cfg := loadViper()
if cfg.DSN == "" {
log.Fatal("database.dsn or DATABASE_DSN required")
}
fmt.Printf("port=%d level=%s\n", cfg.HTTPPort, cfg.LogLevel)
}Lo que esto demuestra:
AutomaticEnv y el reemplazador de clavesmainAppConfig tipado separado de la API de cadenas de viperrequired.fsnotify (viper) o reiniciar el proceso (modelo de operaciones más simple).main o en un paquete config; los paquetes de dominio reciben structs tipados, no llamadas globales a viper.| Fuente | Uso típico | Fuerza de anulación |
|---|---|---|
Set explícito en código | Pruebas | La más alta cuando se usa |
Flags (viper.BindPFlags) | Anulaciones de CLI | Alta |
| Entorno | Secretos de K8s, 12-factor | Alta |
| Archivo de configuración | Valores por defecto por entorno | Media |
SetDefault | Fallbacks seguros | Baja |
| Etiqueta | Efecto |
|---|---|
envconfig:"PORT" | Nombre de la variable de entorno (con prefijo opcional) |
required:"true" | El proceso falla si no está configurado |
default:"8080" | Valor cuando el entorno está ausente |
split_words:"true" | HTTP_PORT se mapea a HTTPPort |
// Prefiera desempaquetar en un struct una vez que las claves de viper se estabilicen
var cfg AppConfig
if err := viper.Unmarshal(&cfg); err != nil {
log.Fatal(err)
}info.viper.GetString ocultan dependencias. Solución: cargar en main, pasar structs AppConfig.http.port vs HTTP_PORT falla silenciosamente sin SetEnvKeyReplacer. Solución: documentar nombres de entorno en tablas de Helm y README.GetString. Solución: validar con if cfg.DSN == "" explícito o required de envconfig.WatchConfig de viper recarga a mitad de la solicitud. Solución: reiniciar pods o habilitar la recarga detrás de un intercambio de punteros atómico más un vaciado.flag.Parse omite las anulaciones de CLI. Solución: analizar primero los flags, luego enlazarlos con viper.BindPFlags.| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
Solo flag + os.Getenv | Dos variables de entorno y un flag de puerto | Decenas de claves en varios archivos |
caarlos0/env | Etiquetas de struct sin la antigüedad de envconfig | Ya se ha estandarizado en envconfig |
koanf | Capas de fusión explícitas sin globales de viper | El equipo conoce viper y quiere una herramienta |
| Solo valores de Helm | La configuración nunca es local | Los desarrolladores necesitan go run sin conexión |
Comience con envconfig cuando toda la configuración provenga de entornos y Secrets de Kubernetes.
Agregue viper cuando necesite valores por defecto de YAML para desarrollo local y flags de características basados en archivos.
Establezca variables de entorno en t.Setenv, escriba archivos YAML temporales o cree literales de AppConfig en pruebas sin tocar viper global cuando sea posible.
A menudo sí para structs AppConfig compartidos; las CLIs pueden agregar enlaces pflag donde los servicios dependen solo del entorno.
Esa página cubre patrones de flags y entorno en general; esta página compara específicamente las bibliotecas viper y envconfig.
Sí: cargue los valores por defecto del archivo con viper, luego anule con envconfig para secretos, pero prefiera un cargador para evitar confusiones de precedencia.
Desempaquete en structs y ejecute go-playground/validator o comprobaciones manuales en puertos, URLs y duraciones.
Genere una tabla a partir de las etiquetas de struct en README, duplíquela en los comentarios de Helm values.yaml y falle el inicio con mensajes de error accionables.
Para CLIs de un solo binario con tres flags, el flag de la biblioteca estándar es más simple y evita una dependencia.
Almacene las claves de los flags en archivos viper o en un proveedor remoto; mantenga los valores por defecto seguros cuando el proveedor no sea accesible.
Sí: un paquete se encarga de la carga, la validación y la representación String() redactada para los registros.
Versiones de la pila: Esta página fue escrita para Go 1.26.x (GC por defecto Green Tea, go fix modernizers - verifique el parche en la compilación), chi (última versión - verifique en la compilación), gin (última versión - verifique en la compilación), echo (última versión - verifique en la compilación), google.golang.org/grpc (última versión - verifique en la compilación), sigs.k8s.io/controller-runtime (última versión - verifique en la compilación), kubebuilder (última versión - verifique en la compilación), tinygo (última versión - verifique los objetivos de la placa en la compilación), wazero (última versión - verifique en la compilación), y golangci-lint (última versión - verifique el conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 19 jul 2026