README.md (28529B)
1 > ## Viper v2 feedback 2 > Viper is heading towards v2 and we would love to hear what _**you**_ would like to see in it. Share your thoughts here: https://forms.gle/R6faU74qPRPAzchZ9 3 > 4 > **Thank you!** 5 6 ![Viper](.github/logo.png?raw=true) 7 8 [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go#configuration) 9 [![run on repl.it](https://repl.it/badge/github/sagikazarmark/Viper-example)](https://repl.it/@sagikazarmark/Viper-example#main.go) 10 11 [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spf13/viper/ci.yaml?branch=master&style=flat-square)](https://github.com/spf13/viper/actions?query=workflow%3ACI) 12 [![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 13 [![Go Report Card](https://goreportcard.com/badge/github.com/spf13/viper?style=flat-square)](https://goreportcard.com/report/github.com/spf13/viper) 14 ![Go Version](https://img.shields.io/badge/go%20version-%3E=1.16-61CFDD.svg?style=flat-square) 15 [![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/spf13/viper)](https://pkg.go.dev/mod/github.com/spf13/viper) 16 17 **Go configuration with fangs!** 18 19 Many Go projects are built using Viper including: 20 21 * [Hugo](http://gohugo.io) 22 * [EMC RexRay](http://rexray.readthedocs.org/en/stable/) 23 * [Imgur’s Incus](https://github.com/Imgur/incus) 24 * [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) 25 * [Docker Notary](https://github.com/docker/Notary) 26 * [BloomApi](https://www.bloomapi.com/) 27 * [doctl](https://github.com/digitalocean/doctl) 28 * [Clairctl](https://github.com/jgsqware/clairctl) 29 * [Mercure](https://mercure.rocks) 30 * [Meshery](https://github.com/meshery/meshery) 31 * [Bearer](https://github.com/bearer/bearer) 32 * [Coder](https://github.com/coder/coder) 33 34 35 ## Install 36 37 ```shell 38 go get github.com/spf13/viper 39 ``` 40 41 **Note:** Viper uses [Go Modules](https://github.com/golang/go/wiki/Modules) to manage dependencies. 42 43 44 ## What is Viper? 45 46 Viper is a complete configuration solution for Go applications including [12-Factor apps](https://12factor.net/#the_twelve_factors). 47 It is designed to work within an application, and can handle all types of configuration needs 48 and formats. It supports: 49 50 * setting defaults 51 * reading from JSON, TOML, YAML, HCL, envfile and Java properties config files 52 * live watching and re-reading of config files (optional) 53 * reading from environment variables 54 * reading from remote config systems (etcd or Consul), and watching changes 55 * reading from command line flags 56 * reading from buffer 57 * setting explicit values 58 59 Viper can be thought of as a registry for all of your applications configuration needs. 60 61 62 ## Why Viper? 63 64 When building a modern application, you don’t want to worry about 65 configuration file formats; you want to focus on building awesome software. 66 Viper is here to help with that. 67 68 Viper does the following for you: 69 70 1. Find, load, and unmarshal a configuration file in JSON, TOML, YAML, HCL, INI, envfile or Java properties formats. 71 2. Provide a mechanism to set default values for your different configuration options. 72 3. Provide a mechanism to set override values for options specified through command line flags. 73 4. Provide an alias system to easily rename parameters without breaking existing code. 74 5. Make it easy to tell the difference between when a user has provided a command line or config file which is the same as the default. 75 76 Viper uses the following precedence order. Each item takes precedence over the item below it: 77 78 * explicit call to `Set` 79 * flag 80 * env 81 * config 82 * key/value store 83 * default 84 85 **Important:** Viper configuration keys are case insensitive. 86 There are ongoing discussions about making that optional. 87 88 89 ## Putting Values into Viper 90 91 ### Establishing Defaults 92 93 A good configuration system will support default values. A default value is not 94 required for a key, but it’s useful in the event that a key hasn't been set via 95 config file, environment variable, remote configuration or flag. 96 97 Examples: 98 99 ```go 100 viper.SetDefault("ContentDir", "content") 101 viper.SetDefault("LayoutDir", "layouts") 102 viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"}) 103 ``` 104 105 ### Reading Config Files 106 107 Viper requires minimal configuration so it knows where to look for config files. 108 Viper supports JSON, TOML, YAML, HCL, INI, envfile and Java Properties files. Viper can search multiple paths, but 109 currently a single Viper instance only supports a single configuration file. 110 Viper does not default to any configuration search paths leaving defaults decision 111 to an application. 112 113 Here is an example of how to use Viper to search for and read a configuration file. 114 None of the specific paths are required, but at least one path should be provided 115 where a configuration file is expected. 116 117 ```go 118 viper.SetConfigName("config") // name of config file (without extension) 119 viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name 120 viper.AddConfigPath("/etc/appname/") // path to look for the config file in 121 viper.AddConfigPath("$HOME/.appname") // call multiple times to add many search paths 122 viper.AddConfigPath(".") // optionally look for config in the working directory 123 err := viper.ReadInConfig() // Find and read the config file 124 if err != nil { // Handle errors reading the config file 125 panic(fmt.Errorf("fatal error config file: %w", err)) 126 } 127 ``` 128 129 You can handle the specific case where no config file is found like this: 130 131 ```go 132 if err := viper.ReadInConfig(); err != nil { 133 if _, ok := err.(viper.ConfigFileNotFoundError); ok { 134 // Config file not found; ignore error if desired 135 } else { 136 // Config file was found but another error was produced 137 } 138 } 139 140 // Config file found and successfully parsed 141 ``` 142 143 *NOTE [since 1.6]:* You can also have a file without an extension and specify the format programmaticaly. For those configuration files that lie in the home of the user without any extension like `.bashrc` 144 145 ### Writing Config Files 146 147 Reading from config files is useful, but at times you want to store all modifications made at run time. 148 For that, a bunch of commands are available, each with its own purpose: 149 150 * WriteConfig - writes the current viper configuration to the predefined path, if exists. Errors if no predefined path. Will overwrite the current config file, if it exists. 151 * SafeWriteConfig - writes the current viper configuration to the predefined path. Errors if no predefined path. Will not overwrite the current config file, if it exists. 152 * WriteConfigAs - writes the current viper configuration to the given filepath. Will overwrite the given file, if it exists. 153 * SafeWriteConfigAs - writes the current viper configuration to the given filepath. Will not overwrite the given file, if it exists. 154 155 As a rule of the thumb, everything marked with safe won't overwrite any file, but just create if not existent, whilst the default behavior is to create or truncate. 156 157 A small examples section: 158 159 ```go 160 viper.WriteConfig() // writes current config to predefined path set by 'viper.AddConfigPath()' and 'viper.SetConfigName' 161 viper.SafeWriteConfig() 162 viper.WriteConfigAs("/path/to/my/.config") 163 viper.SafeWriteConfigAs("/path/to/my/.config") // will error since it has already been written 164 viper.SafeWriteConfigAs("/path/to/my/.other_config") 165 ``` 166 167 ### Watching and re-reading config files 168 169 Viper supports the ability to have your application live read a config file while running. 170 171 Gone are the days of needing to restart a server to have a config take effect, 172 viper powered applications can read an update to a config file while running and 173 not miss a beat. 174 175 Simply tell the viper instance to watchConfig. 176 Optionally you can provide a function for Viper to run each time a change occurs. 177 178 **Make sure you add all of the configPaths prior to calling `WatchConfig()`** 179 180 ```go 181 viper.OnConfigChange(func(e fsnotify.Event) { 182 fmt.Println("Config file changed:", e.Name) 183 }) 184 viper.WatchConfig() 185 ``` 186 187 ### Reading Config from io.Reader 188 189 Viper predefines many configuration sources such as files, environment 190 variables, flags, and remote K/V store, but you are not bound to them. You can 191 also implement your own required configuration source and feed it to viper. 192 193 ```go 194 viper.SetConfigType("yaml") // or viper.SetConfigType("YAML") 195 196 // any approach to require this configuration into your program. 197 var yamlExample = []byte(` 198 Hacker: true 199 name: steve 200 hobbies: 201 - skateboarding 202 - snowboarding 203 - go 204 clothing: 205 jacket: leather 206 trousers: denim 207 age: 35 208 eyes : brown 209 beard: true 210 `) 211 212 viper.ReadConfig(bytes.NewBuffer(yamlExample)) 213 214 viper.Get("name") // this would be "steve" 215 ``` 216 217 ### Setting Overrides 218 219 These could be from a command line flag, or from your own application logic. 220 221 ```go 222 viper.Set("Verbose", true) 223 viper.Set("LogFile", LogFile) 224 ``` 225 226 ### Registering and Using Aliases 227 228 Aliases permit a single value to be referenced by multiple keys 229 230 ```go 231 viper.RegisterAlias("loud", "Verbose") 232 233 viper.Set("verbose", true) // same result as next line 234 viper.Set("loud", true) // same result as prior line 235 236 viper.GetBool("loud") // true 237 viper.GetBool("verbose") // true 238 ``` 239 240 ### Working with Environment Variables 241 242 Viper has full support for environment variables. This enables 12 factor 243 applications out of the box. There are five methods that exist to aid working 244 with ENV: 245 246 * `AutomaticEnv()` 247 * `BindEnv(string...) : error` 248 * `SetEnvPrefix(string)` 249 * `SetEnvKeyReplacer(string...) *strings.Replacer` 250 * `AllowEmptyEnv(bool)` 251 252 _When working with ENV variables, it’s important to recognize that Viper 253 treats ENV variables as case sensitive._ 254 255 Viper provides a mechanism to try to ensure that ENV variables are unique. By 256 using `SetEnvPrefix`, you can tell Viper to use a prefix while reading from 257 the environment variables. Both `BindEnv` and `AutomaticEnv` will use this 258 prefix. 259 260 `BindEnv` takes one or more parameters. The first parameter is the key name, the 261 rest are the name of the environment variables to bind to this key. If more than 262 one are provided, they will take precedence in the specified order. The name of 263 the environment variable is case sensitive. If the ENV variable name is not provided, then 264 Viper will automatically assume that the ENV variable matches the following format: prefix + "_" + the key name in ALL CAPS. When you explicitly provide the ENV variable name (the second parameter), 265 it **does not** automatically add the prefix. For example if the second parameter is "id", 266 Viper will look for the ENV variable "ID". 267 268 One important thing to recognize when working with ENV variables is that the 269 value will be read each time it is accessed. Viper does not fix the value when 270 the `BindEnv` is called. 271 272 `AutomaticEnv` is a powerful helper especially when combined with 273 `SetEnvPrefix`. When called, Viper will check for an environment variable any 274 time a `viper.Get` request is made. It will apply the following rules. It will 275 check for an environment variable with a name matching the key uppercased and 276 prefixed with the `EnvPrefix` if set. 277 278 `SetEnvKeyReplacer` allows you to use a `strings.Replacer` object to rewrite Env 279 keys to an extent. This is useful if you want to use `-` or something in your 280 `Get()` calls, but want your environmental variables to use `_` delimiters. An 281 example of using it can be found in `viper_test.go`. 282 283 Alternatively, you can use `EnvKeyReplacer` with `NewWithOptions` factory function. 284 Unlike `SetEnvKeyReplacer`, it accepts a `StringReplacer` interface allowing you to write custom string replacing logic. 285 286 By default empty environment variables are considered unset and will fall back to 287 the next configuration source. To treat empty environment variables as set, use 288 the `AllowEmptyEnv` method. 289 290 #### Env example 291 292 ```go 293 SetEnvPrefix("spf") // will be uppercased automatically 294 BindEnv("id") 295 296 os.Setenv("SPF_ID", "13") // typically done outside of the app 297 298 id := Get("id") // 13 299 ``` 300 301 ### Working with Flags 302 303 Viper has the ability to bind to flags. Specifically, Viper supports `Pflags` 304 as used in the [Cobra](https://github.com/spf13/cobra) library. 305 306 Like `BindEnv`, the value is not set when the binding method is called, but when 307 it is accessed. This means you can bind as early as you want, even in an 308 `init()` function. 309 310 For individual flags, the `BindPFlag()` method provides this functionality. 311 312 Example: 313 314 ```go 315 serverCmd.Flags().Int("port", 1138, "Port to run Application server on") 316 viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) 317 ``` 318 319 You can also bind an existing set of pflags (pflag.FlagSet): 320 321 Example: 322 323 ```go 324 pflag.Int("flagname", 1234, "help message for flagname") 325 326 pflag.Parse() 327 viper.BindPFlags(pflag.CommandLine) 328 329 i := viper.GetInt("flagname") // retrieve values from viper instead of pflag 330 ``` 331 332 The use of [pflag](https://github.com/spf13/pflag/) in Viper does not preclude 333 the use of other packages that use the [flag](https://golang.org/pkg/flag/) 334 package from the standard library. The pflag package can handle the flags 335 defined for the flag package by importing these flags. This is accomplished 336 by a calling a convenience function provided by the pflag package called 337 AddGoFlagSet(). 338 339 Example: 340 341 ```go 342 package main 343 344 import ( 345 "flag" 346 "github.com/spf13/pflag" 347 ) 348 349 func main() { 350 351 // using standard library "flag" package 352 flag.Int("flagname", 1234, "help message for flagname") 353 354 pflag.CommandLine.AddGoFlagSet(flag.CommandLine) 355 pflag.Parse() 356 viper.BindPFlags(pflag.CommandLine) 357 358 i := viper.GetInt("flagname") // retrieve value from viper 359 360 // ... 361 } 362 ``` 363 364 #### Flag interfaces 365 366 Viper provides two Go interfaces to bind other flag systems if you don’t use `Pflags`. 367 368 `FlagValue` represents a single flag. This is a very simple example on how to implement this interface: 369 370 ```go 371 type myFlag struct {} 372 func (f myFlag) HasChanged() bool { return false } 373 func (f myFlag) Name() string { return "my-flag-name" } 374 func (f myFlag) ValueString() string { return "my-flag-value" } 375 func (f myFlag) ValueType() string { return "string" } 376 ``` 377 378 Once your flag implements this interface, you can simply tell Viper to bind it: 379 380 ```go 381 viper.BindFlagValue("my-flag-name", myFlag{}) 382 ``` 383 384 `FlagValueSet` represents a group of flags. This is a very simple example on how to implement this interface: 385 386 ```go 387 type myFlagSet struct { 388 flags []myFlag 389 } 390 391 func (f myFlagSet) VisitAll(fn func(FlagValue)) { 392 for _, flag := range flags { 393 fn(flag) 394 } 395 } 396 ``` 397 398 Once your flag set implements this interface, you can simply tell Viper to bind it: 399 400 ```go 401 fSet := myFlagSet{ 402 flags: []myFlag{myFlag{}, myFlag{}}, 403 } 404 viper.BindFlagValues("my-flags", fSet) 405 ``` 406 407 ### Remote Key/Value Store Support 408 409 To enable remote support in Viper, do a blank import of the `viper/remote` 410 package: 411 412 `import _ "github.com/spf13/viper/remote"` 413 414 Viper will read a config string (as JSON, TOML, YAML, HCL or envfile) retrieved from a path 415 in a Key/Value store such as etcd or Consul. These values take precedence over 416 default values, but are overridden by configuration values retrieved from disk, 417 flags, or environment variables. 418 419 Viper uses [crypt](https://github.com/bketelsen/crypt) to retrieve 420 configuration from the K/V store, which means that you can store your 421 configuration values encrypted and have them automatically decrypted if you have 422 the correct gpg keyring. Encryption is optional. 423 424 You can use remote configuration in conjunction with local configuration, or 425 independently of it. 426 427 `crypt` has a command-line helper that you can use to put configurations in your 428 K/V store. `crypt` defaults to etcd on http://127.0.0.1:4001. 429 430 ```bash 431 $ go get github.com/bketelsen/crypt/bin/crypt 432 $ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json 433 ``` 434 435 Confirm that your value was set: 436 437 ```bash 438 $ crypt get -plaintext /config/hugo.json 439 ``` 440 441 See the `crypt` documentation for examples of how to set encrypted values, or 442 how to use Consul. 443 444 ### Remote Key/Value Store Example - Unencrypted 445 446 #### etcd 447 ```go 448 viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json") 449 viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv" 450 err := viper.ReadRemoteConfig() 451 ``` 452 453 #### etcd3 454 ```go 455 viper.AddRemoteProvider("etcd3", "http://127.0.0.1:4001","/config/hugo.json") 456 viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv" 457 err := viper.ReadRemoteConfig() 458 ``` 459 460 #### Consul 461 You need to set a key to Consul key/value storage with JSON value containing your desired config. 462 For example, create a Consul key/value store key `MY_CONSUL_KEY` with value: 463 464 ```json 465 { 466 "port": 8080, 467 "hostname": "myhostname.com" 468 } 469 ``` 470 471 ```go 472 viper.AddRemoteProvider("consul", "localhost:8500", "MY_CONSUL_KEY") 473 viper.SetConfigType("json") // Need to explicitly set this to json 474 err := viper.ReadRemoteConfig() 475 476 fmt.Println(viper.Get("port")) // 8080 477 fmt.Println(viper.Get("hostname")) // myhostname.com 478 ``` 479 480 #### Firestore 481 482 ```go 483 viper.AddRemoteProvider("firestore", "google-cloud-project-id", "collection/document") 484 viper.SetConfigType("json") // Config's format: "json", "toml", "yaml", "yml" 485 err := viper.ReadRemoteConfig() 486 ``` 487 488 Of course, you're allowed to use `SecureRemoteProvider` also 489 490 ### Remote Key/Value Store Example - Encrypted 491 492 ```go 493 viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg") 494 viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv" 495 err := viper.ReadRemoteConfig() 496 ``` 497 498 ### Watching Changes in etcd - Unencrypted 499 500 ```go 501 // alternatively, you can create a new viper instance. 502 var runtime_viper = viper.New() 503 504 runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml") 505 runtime_viper.SetConfigType("yaml") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv" 506 507 // read from remote config the first time. 508 err := runtime_viper.ReadRemoteConfig() 509 510 // unmarshal config 511 runtime_viper.Unmarshal(&runtime_conf) 512 513 // open a goroutine to watch remote changes forever 514 go func(){ 515 for { 516 time.Sleep(time.Second * 5) // delay after each request 517 518 // currently, only tested with etcd support 519 err := runtime_viper.WatchRemoteConfig() 520 if err != nil { 521 log.Errorf("unable to read remote config: %v", err) 522 continue 523 } 524 525 // unmarshal new config into our runtime config struct. you can also use channel 526 // to implement a signal to notify the system of the changes 527 runtime_viper.Unmarshal(&runtime_conf) 528 } 529 }() 530 ``` 531 532 ## Getting Values From Viper 533 534 In Viper, there are a few ways to get a value depending on the value’s type. 535 The following functions and methods exist: 536 537 * `Get(key string) : interface{}` 538 * `GetBool(key string) : bool` 539 * `GetFloat64(key string) : float64` 540 * `GetInt(key string) : int` 541 * `GetIntSlice(key string) : []int` 542 * `GetString(key string) : string` 543 * `GetStringMap(key string) : map[string]interface{}` 544 * `GetStringMapString(key string) : map[string]string` 545 * `GetStringSlice(key string) : []string` 546 * `GetTime(key string) : time.Time` 547 * `GetDuration(key string) : time.Duration` 548 * `IsSet(key string) : bool` 549 * `AllSettings() : map[string]interface{}` 550 551 One important thing to recognize is that each Get function will return a zero 552 value if it’s not found. To check if a given key exists, the `IsSet()` method 553 has been provided. 554 555 Example: 556 ```go 557 viper.GetString("logfile") // case-insensitive Setting & Getting 558 if viper.GetBool("verbose") { 559 fmt.Println("verbose enabled") 560 } 561 ``` 562 ### Accessing nested keys 563 564 The accessor methods also accept formatted paths to deeply nested keys. For 565 example, if the following JSON file is loaded: 566 567 ```json 568 { 569 "host": { 570 "address": "localhost", 571 "port": 5799 572 }, 573 "datastore": { 574 "metric": { 575 "host": "127.0.0.1", 576 "port": 3099 577 }, 578 "warehouse": { 579 "host": "198.0.0.1", 580 "port": 2112 581 } 582 } 583 } 584 585 ``` 586 587 Viper can access a nested field by passing a `.` delimited path of keys: 588 589 ```go 590 GetString("datastore.metric.host") // (returns "127.0.0.1") 591 ``` 592 593 This obeys the precedence rules established above; the search for the path 594 will cascade through the remaining configuration registries until found. 595 596 For example, given this configuration file, both `datastore.metric.host` and 597 `datastore.metric.port` are already defined (and may be overridden). If in addition 598 `datastore.metric.protocol` was defined in the defaults, Viper would also find it. 599 600 However, if `datastore.metric` was overridden (by a flag, an environment variable, 601 the `Set()` method, …) with an immediate value, then all sub-keys of 602 `datastore.metric` become undefined, they are “shadowed” by the higher-priority 603 configuration level. 604 605 Viper can access array indices by using numbers in the path. For example: 606 607 ```jsonc 608 { 609 "host": { 610 "address": "localhost", 611 "ports": [ 612 5799, 613 6029 614 ] 615 }, 616 "datastore": { 617 "metric": { 618 "host": "127.0.0.1", 619 "port": 3099 620 }, 621 "warehouse": { 622 "host": "198.0.0.1", 623 "port": 2112 624 } 625 } 626 } 627 628 GetInt("host.ports.1") // returns 6029 629 630 ``` 631 632 Lastly, if there exists a key that matches the delimited key path, its value 633 will be returned instead. E.g. 634 635 ```jsonc 636 { 637 "datastore.metric.host": "0.0.0.0", 638 "host": { 639 "address": "localhost", 640 "port": 5799 641 }, 642 "datastore": { 643 "metric": { 644 "host": "127.0.0.1", 645 "port": 3099 646 }, 647 "warehouse": { 648 "host": "198.0.0.1", 649 "port": 2112 650 } 651 } 652 } 653 654 GetString("datastore.metric.host") // returns "0.0.0.0" 655 ``` 656 657 ### Extracting a sub-tree 658 659 When developing reusable modules, it's often useful to extract a subset of the configuration 660 and pass it to a module. This way the module can be instantiated more than once, with different configurations. 661 662 For example, an application might use multiple different cache stores for different purposes: 663 664 ```yaml 665 cache: 666 cache1: 667 max-items: 100 668 item-size: 64 669 cache2: 670 max-items: 200 671 item-size: 80 672 ``` 673 674 We could pass the cache name to a module (eg. `NewCache("cache1")`), 675 but it would require weird concatenation for accessing config keys and would be less separated from the global config. 676 677 So instead of doing that let's pass a Viper instance to the constructor that represents a subset of the configuration: 678 679 ```go 680 cache1Config := viper.Sub("cache.cache1") 681 if cache1Config == nil { // Sub returns nil if the key cannot be found 682 panic("cache configuration not found") 683 } 684 685 cache1 := NewCache(cache1Config) 686 ``` 687 688 **Note:** Always check the return value of `Sub`. It returns `nil` if a key cannot be found. 689 690 Internally, the `NewCache` function can address `max-items` and `item-size` keys directly: 691 692 ```go 693 func NewCache(v *Viper) *Cache { 694 return &Cache{ 695 MaxItems: v.GetInt("max-items"), 696 ItemSize: v.GetInt("item-size"), 697 } 698 } 699 ``` 700 701 The resulting code is easy to test, since it's decoupled from the main config structure, 702 and easier to reuse (for the same reason). 703 704 705 ### Unmarshaling 706 707 You also have the option of Unmarshaling all or a specific value to a struct, map, 708 etc. 709 710 There are two methods to do this: 711 712 * `Unmarshal(rawVal interface{}) : error` 713 * `UnmarshalKey(key string, rawVal interface{}) : error` 714 715 Example: 716 717 ```go 718 type config struct { 719 Port int 720 Name string 721 PathMap string `mapstructure:"path_map"` 722 } 723 724 var C config 725 726 err := viper.Unmarshal(&C) 727 if err != nil { 728 t.Fatalf("unable to decode into struct, %v", err) 729 } 730 ``` 731 732 If you want to unmarshal configuration where the keys themselves contain dot (the default key delimiter), 733 you have to change the delimiter: 734 735 ```go 736 v := viper.NewWithOptions(viper.KeyDelimiter("::")) 737 738 v.SetDefault("chart::values", map[string]interface{}{ 739 "ingress": map[string]interface{}{ 740 "annotations": map[string]interface{}{ 741 "traefik.frontend.rule.type": "PathPrefix", 742 "traefik.ingress.kubernetes.io/ssl-redirect": "true", 743 }, 744 }, 745 }) 746 747 type config struct { 748 Chart struct{ 749 Values map[string]interface{} 750 } 751 } 752 753 var C config 754 755 v.Unmarshal(&C) 756 ``` 757 758 Viper also supports unmarshaling into embedded structs: 759 760 ```go 761 /* 762 Example config: 763 764 module: 765 enabled: true 766 token: 89h3f98hbwf987h3f98wenf89ehf 767 */ 768 type config struct { 769 Module struct { 770 Enabled bool 771 772 moduleConfig `mapstructure:",squash"` 773 } 774 } 775 776 // moduleConfig could be in a module specific package 777 type moduleConfig struct { 778 Token string 779 } 780 781 var C config 782 783 err := viper.Unmarshal(&C) 784 if err != nil { 785 t.Fatalf("unable to decode into struct, %v", err) 786 } 787 ``` 788 789 Viper uses [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) under the hood for unmarshaling values which uses `mapstructure` tags by default. 790 791 ### Decoding custom formats 792 793 A frequently requested feature for Viper is adding more value formats and decoders. 794 For example, parsing character (dot, comma, semicolon, etc) separated strings into slices. 795 796 This is already available in Viper using mapstructure decode hooks. 797 798 Read more about the details in [this blog post](https://sagikazarmark.hu/blog/decoding-custom-formats-with-viper/). 799 800 ### Marshalling to string 801 802 You may need to marshal all the settings held in viper into a string rather than write them to a file. 803 You can use your favorite format's marshaller with the config returned by `AllSettings()`. 804 805 ```go 806 import ( 807 yaml "gopkg.in/yaml.v2" 808 // ... 809 ) 810 811 func yamlStringSettings() string { 812 c := viper.AllSettings() 813 bs, err := yaml.Marshal(c) 814 if err != nil { 815 log.Fatalf("unable to marshal config to YAML: %v", err) 816 } 817 return string(bs) 818 } 819 ``` 820 821 ## Viper or Vipers? 822 823 Viper comes ready to use out of the box. There is no configuration or 824 initialization needed to begin using Viper. Since most applications will want 825 to use a single central repository for their configuration, the viper package 826 provides this. It is similar to a singleton. 827 828 In all of the examples above, they demonstrate using viper in its singleton 829 style approach. 830 831 ### Working with multiple vipers 832 833 You can also create many different vipers for use in your application. Each will 834 have its own unique set of configurations and values. Each can read from a 835 different config file, key value store, etc. All of the functions that viper 836 package supports are mirrored as methods on a viper. 837 838 Example: 839 840 ```go 841 x := viper.New() 842 y := viper.New() 843 844 x.SetDefault("ContentDir", "content") 845 y.SetDefault("ContentDir", "foobar") 846 847 //... 848 ``` 849 850 When working with multiple vipers, it is up to the user to keep track of the 851 different vipers. 852 853 854 ## Q & A 855 856 ### Why is it called “Viper”? 857 858 A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe)) 859 to [Cobra](https://github.com/spf13/cobra). While both can operate completely 860 independently, together they make a powerful pair to handle much of your 861 application foundation needs. 862 863 ### Why is it called “Cobra”? 864 865 Is there a better name for a [commander](http://en.wikipedia.org/wiki/Cobra_Commander)? 866 867 ### Does Viper support case sensitive keys? 868 869 **tl;dr:** No. 870 871 Viper merges configuration from various sources, many of which are either case insensitive or uses different casing than the rest of the sources (eg. env vars). 872 In order to provide the best experience when using multiple sources, the decision has been made to make all keys case insensitive. 873 874 There has been several attempts to implement case sensitivity, but unfortunately it's not that trivial. We might take a stab at implementing it in [Viper v2](https://github.com/spf13/viper/issues/772), but despite the initial noise, it does not seem to be requested that much. 875 876 You can vote for case sensitivity by filling out this feedback form: https://forms.gle/R6faU74qPRPAzchZ9 877 878 ### Is it safe to concurrently read and write to a viper? 879 880 No, you will need to synchronize access to the viper yourself (for example by using the `sync` package). Concurrent reads and writes can cause a panic. 881 882 ## Troubleshooting 883 884 See [TROUBLESHOOTING.md](TROUBLESHOOTING.md).