Configuração de aplicações em Go (Golang): de variáveis de ambiente a estruturas YAML complexas
Configuração é um dos aspectos-chave de qualquer aplicação de produção. Em Go (Golang), o ecossistema oferece ferramentas flexíveis e poderosas para gerenciar configurações, adaptadas a diferentes cenários: desde aplicações simples 12-factor até microsserviços com dezenas de parâmetros. Neste artigo, abordaremos as principais abordagens, bibliotecas populares e melhores práticas de configuração de aplicações Go.
Por que é necessária uma configuração separada?
Codificar parâmetros diretamente (hardcode) é um antipadrão. A configuração permite:
- Alterar o comportamento da aplicação sem recompilação;
- Separar configurações para diferentes ambientes (dev/staging/prod);
- Garantir segurança (segredos não entram no repositório);
- Simplificar a implantação em contêineres e plataformas em nuvem.
Abordagem básica: variáveis de ambiente
A biblioteca padrão do Go fornece a função os.Getenv. Esta é uma forma minimalista, mas eficaz, para projetos pequenos, seguindo os princípios do 12-factor app.
package main
import ( "fmt" "os")
type Config struct { Port string DBHost string DBUser string}
func loadConfig() Config { return Config{ Port: getEnv("APP_PORT", "8080"), DBHost: getEnv("DB_HOST", "localhost"), DBUser: getEnv("DB_USER", "admin"), }}
func getEnv(key, fallback string) string { if value, ok := os.LookupEnv(key); ok { return value } return fallback}
func main() { cfg := loadConfig() fmt.Printf("Server starting on port %s", cfg.Port)}Biblioteca Viper: o "canivete suíço" da configuração
Viper (dos criadores do Cobra) é a biblioteca mais popular para configuração em Go. Ela suporta múltiplos formatos, busca em várias fontes e hierarquia de configurações.
Principais recursos do Viper:
- Leitura de YAML, JSON, TOML, HCL, INI, envfile, Java properties;
- Suporte a variáveis de ambiente com prefixos personalizados;
- Definição de valores padrão;
- Atualização dinâmica de configuração (live reload);
- Integração com fontes remotas (etcd, Consul, Firebase).
Exemplo de uso do Viper com YAML:
package main
import ( "fmt" "github.com/spf13/viper")
type AppConfig struct { Server ServerConfig `mapstructure:"server"` Database DatabaseConfig `mapstructure:"database"`}
type ServerConfig struct { Port int `mapstructure:"port"` Host string `mapstructure:"host"`}
type DatabaseConfig struct { URL string `mapstructure:"url"` Pool int `mapstructure:"pool"`}
func main() { viper.SetConfigName("config") // nome do arquivo sem extensão viper.SetConfigType("yaml") // formato viper.AddConfigPath(".") // caminho de busca viper.AddConfigPath("./config/")
// Leitura de variáveis de ambiente com prefixo APP_ viper.AutomaticEnv() viper.SetEnvPrefix("APP")
if err := viper.ReadInConfig(); err != nil { panic(fmt.Errorf("fatal error config file: %s", err)) }
var cfg AppConfig if err := viper.Unmarshal(&cfg); err != nil { panic(fmt.Errorf("unable to decode into struct: %s", err)) }
fmt.Printf("Server: %s:%d", cfg.Server.Host, cfg.Server.Port) fmt.Printf("Database URL: %s", cfg.Database.URL)}Exemplo de arquivo config.yaml:
server: port: 8080 host: "0.0.0.0"database: url: "postgres://user:pass@localhost:5432/app" pool: 10Biblioteca envconfig: simplicidade e declaratividade
Se você não precisa de formatos complexos, apenas variáveis de ambiente — Também na biblioteca
Recommendations