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