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