Scripts2026年4月13日·1 分钟阅读

Viper — Complete Configuration Solution for Go

Viper is the most popular configuration library for Go applications. It reads config from JSON, TOML, YAML, HCL, envfile, and Java properties files, supports environment variables, remote config systems, and live watching for config changes.

SC
Script Depot · Community
快速使用

先拿来用,再决定要不要深挖

这里应该同时让用户和 Agent 知道第一步该复制什么、安装什么、落到哪里。

package main

import (
    "fmt"
    "github.com/spf13/viper"
)

func main() {
    viper.SetConfigName("config")
    viper.SetConfigType("yaml")
    viper.AddConfigPath(".")
    viper.AutomaticEnv()

    viper.SetDefault("port", 8080)
    viper.SetDefault("debug", false)

    if err := viper.ReadInConfig(); err != nil {
        fmt.Printf("No config file found, using defaults\n")
    }

    fmt.Printf("Port: %d\n", viper.GetInt("port"))
    fmt.Printf("Debug: %v\n", viper.GetBool("debug"))
    fmt.Printf("DB Host: %s\n", viper.GetString("database.host"))
}
# config.yaml
port: 3000
debug: true
database:
  host: localhost
  port: 5432
  name: myapp
  password: ${DB_PASSWORD}  # resolved from env

Introduction

Viper handles all configuration needs for Go applications. Created by Steve Francia (also creator of Cobra and Hugo), Viper provides a unified interface for reading configuration from files, environment variables, command-line flags, and remote systems like etcd and Consul.

With over 30,000 GitHub stars, Viper is the companion to Cobra for CLI applications and the standard configuration library across the Go ecosystem. The Cobra+Viper combination powers the configuration systems of Kubernetes, Docker, Hugo, and many other tools.

What Viper Does

Viper reads and merges configuration from multiple sources with a clear precedence order: explicit Set calls > flags > environment variables > config file > key/value store > defaults. It supports nested keys (database.host), type coercion, unmarshaling to structs, and live config watching.

Architecture Overview

[Configuration Sources (precedence order)]
1. viper.Set()           — explicit overrides
2. Command-line flags    — via pflag/Cobra
3. Environment variables — APP_DATABASE_HOST
4. Config fileconfig.yaml
5. Remote KV storeetcd, Consul
6. Defaults              — viper.SetDefault()
        |
   [Viper Core]
   Merge all sources
   Type coercion
   Nested key access
        |
   [Access Methods]
   viper.GetString("key")
   viper.GetInt("key")
   viper.Unmarshal(&config)
   viper.WatchConfig()

Self-Hosting & Configuration

import (
    "github.com/spf13/viper"
    "github.com/spf13/cobra"
    "log"
)

type Config struct {
    Port     int      `mapstructure:"port"`
    Debug    bool     `mapstructure:"debug"`
    Database DBConfig `mapstructure:"database"`
}

type DBConfig struct {
    Host     string `mapstructure:"host"`
    Port     int    `mapstructure:"port"`
    Name     string `mapstructure:"name"`
    Password string `mapstructure:"password"`
}

func LoadConfig() (*Config, error) {
    viper.SetConfigName("config")
    viper.SetConfigType("yaml")
    viper.AddConfigPath(".")
    viper.AddConfigPath("$HOME/.myapp")
    viper.AddConfigPath("/etc/myapp")

    // Environment variable binding
    viper.SetEnvPrefix("MYAPP")
    viper.AutomaticEnv()
    viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
    // MYAPP_DATABASE_HOST -> database.host

    viper.SetDefault("port", 8080)
    viper.SetDefault("database.host", "localhost")
    viper.SetDefault("database.port", 5432)

    if err := viper.ReadInConfig(); err != nil {
        log.Printf("No config file: %v", err)
    }

    var config Config
    if err := viper.Unmarshal(&config); err != nil {
        return nil, err
    }

    // Watch for config changes
    viper.WatchConfig()
    viper.OnConfigChange(func(e fsnotify.Event) {
        log.Printf("Config changed: %s", e.Name)
        viper.Unmarshal(&config)
    })

    return &config, nil
}

Key Features

  • Multi-Format — JSON, TOML, YAML, HCL, envfile, Java properties
  • Env Variables — automatic binding with prefix and key replacement
  • Cobra Integration — seamless flag binding with Cobra CLI
  • Nested Keys — access deep config with dot notation (db.host)
  • Struct Unmarshaling — decode config into Go structs
  • Live Watching — detect and reload config file changes
  • Remote Config — read from etcd, Consul, and Firestore
  • Defaults — set sensible defaults with clear precedence

Comparison with Similar Tools

Feature Viper envconfig koanf cleanenv
File Formats 6+ No (env only) 10+ YAML, env
Env Variables Yes Yes (primary) Yes Yes
Cobra Integration Native No No No
Watch/Reload Yes No Yes No
Remote Config etcd, Consul No Various No
Complexity Moderate Very Low Moderate Low
Best For Full-featured apps Simple env config Flexible config Struct-based

FAQ

Q: How does Viper work with Cobra? A: Bind Cobra flags to Viper keys with viper.BindPFlag("port", cmd.Flags().Lookup("port")). This lets config file, env var, and CLI flag all set the same value with proper precedence.

Q: Can I use Viper without config files? A: Yes. Use viper.SetDefault() for defaults and viper.AutomaticEnv() for environment variables. Config files are optional.

Q: How do I handle secrets? A: Use environment variables for secrets (never put them in config files). Viper.AutomaticEnv() reads them automatically. For production, use a secrets manager and inject as env vars.

Q: Is Viper thread-safe? A: Viper is safe for concurrent reads. For concurrent writes (rare), use viper.Set() which is also safe. Config watching runs in a separate goroutine safely.

Sources

讨论

登录后参与讨论。
还没有评论,来写第一条吧。

相关资产