goviper-go

Viper mapping environment variable to struct member


Here's my config.yaml file

server:
  port: 5000

here's my logic to unmarshal using viper

type Configurations struct {
    Server ServerConfig
}

type ServerConfig struct {
    Port int
}

// LoadConfig reads configuration from file or environment variables.
func LoadConfig(path string) (config Configurations, err error) {
    viper.AddConfigPath(path)
    viper.SetConfigName("config")
    viper.SetConfigType("yaml")

    viper.AutomaticEnv()

    err = viper.ReadInConfig()
    if err != nil {
        return
    }

    err = viper.Unmarshal(&config)
    return
}

I have set env variable export PORT=9000, now my question is how can I map the environmental variable PORT to Configurations.ServerConfig.Port. I would like to have config file with default values for dev and would like my app to read/override config from env variables on production, how can I achieve this using viper.

I see following options

  1. set SERVER_PORT and then use replacer like below to unmarshal it to struct
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
  1. Go viper .yaml values environment variables override

But I would like to map variable PORT to the struct member, probably because my hosting service provider sets PORT env variable, and I cannot use 2nd point because I would like to have yaml for default values.


Solution

  • You can use viper.BindEnv(string...) error to bind specific environment variables to configuration.

    From Working with Environment Variables:

    BindEnv takes one or more parameters. The first parameter is the key name, the rest are the name of the environment variables to bind to this key. If more than one are provided, they will take precedence in the specified order.

    Here the configuration key for the port is server.port, and the environment variable PORT should bind to it.

    ...
    viper.AutomaticEnv()
    
    
    err = viper.BindEnv("server.port", "PORT")
    if err != nil {
        return
    }
    
    
    err = viper.ReadInConfig()
    ...
    

    With this change in place a call like PORT=9999 ./yourbinary picks up PORT and writes it into server.port. From there, it will be unmarshalled into your struct.