vendor/github.com/spf13/viper/README.md
changeset 251 1c52a0eeb952
parent 242 2a9ec03fe5a1
child 256 6d9efbef00a9
equal deleted inserted replaced
250:c040f992052f 251:1c52a0eeb952
     1 ![viper logo](https://cloud.githubusercontent.com/assets/173412/10886745/998df88a-8151-11e5-9448-4736db51020d.png)
     1 ![viper logo](https://cloud.githubusercontent.com/assets/173412/10886745/998df88a-8151-11e5-9448-4736db51020d.png)
     2 
     2 
     3 Go configuration with fangs!
     3 Go configuration with fangs!
       
     4 
       
     5 [![Actions](https://github.com/spf13/viper/workflows/CI/badge.svg)](https://github.com/spf13/viper)
       
     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 [![GoDoc](https://godoc.org/github.com/spf13/viper?status.svg)](https://godoc.org/github.com/spf13/viper)
     4 
     8 
     5 Many Go projects are built using Viper including:
     9 Many Go projects are built using Viper including:
     6 
    10 
     7 * [Hugo](http://gohugo.io)
    11 * [Hugo](http://gohugo.io)
     8 * [EMC RexRay](http://rexray.readthedocs.org/en/stable/)
    12 * [EMC RexRay](http://rexray.readthedocs.org/en/stable/)
    10 * [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
    14 * [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
    11 * [Docker Notary](https://github.com/docker/Notary)
    15 * [Docker Notary](https://github.com/docker/Notary)
    12 * [BloomApi](https://www.bloomapi.com/)
    16 * [BloomApi](https://www.bloomapi.com/)
    13 * [doctl](https://github.com/digitalocean/doctl)
    17 * [doctl](https://github.com/digitalocean/doctl)
    14 * [Clairctl](https://github.com/jgsqware/clairctl)
    18 * [Clairctl](https://github.com/jgsqware/clairctl)
    15 
    19 * [Mercure](https://mercure.rocks)
    16 [![Build Status](https://travis-ci.org/spf13/viper.svg)](https://travis-ci.org/spf13/viper) [![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) [![GoDoc](https://godoc.org/github.com/spf13/viper?status.svg)](https://godoc.org/github.com/spf13/viper)
    20 
       
    21 
       
    22 ## Install
       
    23 
       
    24 ```console
       
    25 go get github.com/spf13/viper
       
    26 ```
    17 
    27 
    18 
    28 
    19 ## What is Viper?
    29 ## What is Viper?
    20 
    30 
    21 Viper is a complete configuration solution for Go applications including 12-Factor apps. It is designed
    31 Viper is a complete configuration solution for Go applications including 12-Factor apps. It is designed
    22 to work within an application, and can handle all types of configuration needs
    32 to work within an application, and can handle all types of configuration needs
    23 and formats. It supports:
    33 and formats. It supports:
    24 
    34 
    25 * setting defaults
    35 * setting defaults
    26 * reading from JSON, TOML, YAML, HCL, and Java properties config files
    36 * reading from JSON, TOML, YAML, HCL, envfile and Java properties config files
    27 * live watching and re-reading of config files (optional)
    37 * live watching and re-reading of config files (optional)
    28 * reading from environment variables
    38 * reading from environment variables
    29 * reading from remote config systems (etcd or Consul), and watching changes
    39 * reading from remote config systems (etcd or Consul), and watching changes
    30 * reading from command line flags
    40 * reading from command line flags
    31 * reading from buffer
    41 * reading from buffer
    32 * setting explicit values
    42 * setting explicit values
    33 
    43 
    34 Viper can be thought of as a registry for all of your applications
    44 Viper can be thought of as a registry for all of your applications configuration needs.
    35 configuration needs.
    45 
    36 
    46 
    37 ## Why Viper?
    47 ## Why Viper?
    38 
    48 
    39 When building a modern application, you don’t want to worry about
    49 When building a modern application, you don’t want to worry about
    40 configuration file formats; you want to focus on building awesome software.
    50 configuration file formats; you want to focus on building awesome software.
    41 Viper is here to help with that.
    51 Viper is here to help with that.
    42 
    52 
    43 Viper does the following for you:
    53 Viper does the following for you:
    44 
    54 
    45 1. Find, load, and unmarshal a configuration file in JSON, TOML, YAML, HCL, or Java properties formats.
    55 1. Find, load, and unmarshal a configuration file in JSON, TOML, YAML, HCL, INI, envfile or Java properties formats.
    46 2. Provide a mechanism to set default values for your different
    56 2. Provide a mechanism to set default values for your different configuration options.
    47    configuration options.
    57 3. Provide a mechanism to set override values for options specified through command line flags.
    48 3. Provide a mechanism to set override values for options specified through
    58 4. Provide an alias system to easily rename parameters without breaking existing code.
    49    command line flags.
    59 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.
    50 4. Provide an alias system to easily rename parameters without breaking existing
    60 
    51    code.
    61 Viper uses the following precedence order. Each item takes precedence over the item below it:
    52 5. Make it easy to tell the difference between when a user has provided a
    62 
    53    command line or config file which is the same as the default.
    63  * explicit call to `Set`
    54 
       
    55 Viper uses the following precedence order. Each item takes precedence over the
       
    56 item below it:
       
    57 
       
    58  * explicit call to Set
       
    59  * flag
    64  * flag
    60  * env
    65  * env
    61  * config
    66  * config
    62  * key/value store
    67  * key/value store
    63  * default
    68  * default
    64 
    69 
    65 Viper configuration keys are case insensitive.
    70 **Important:** Viper configuration keys are case insensitive.
       
    71 There are ongoing discussions about making that optional.
       
    72 
    66 
    73 
    67 ## Putting Values into Viper
    74 ## Putting Values into Viper
    68 
    75 
    69 ### Establishing Defaults
    76 ### Establishing Defaults
    70 
    77 
    71 A good configuration system will support default values. A default value is not
    78 A good configuration system will support default values. A default value is not
    72 required for a key, but it’s useful in the event that a key hasn’t been set via
    79 required for a key, but it’s useful in the event that a key hasn't been set via
    73 config file, environment variable, remote configuration or flag.
    80 config file, environment variable, remote configuration or flag.
    74 
    81 
    75 Examples:
    82 Examples:
    76 
    83 
    77 ```go
    84 ```go
    81 ```
    88 ```
    82 
    89 
    83 ### Reading Config Files
    90 ### Reading Config Files
    84 
    91 
    85 Viper requires minimal configuration so it knows where to look for config files.
    92 Viper requires minimal configuration so it knows where to look for config files.
    86 Viper supports JSON, TOML, YAML, HCL, and Java Properties files. Viper can search multiple paths, but
    93 Viper supports JSON, TOML, YAML, HCL, INI, envfile and Java Properties files. Viper can search multiple paths, but
    87 currently a single Viper instance only supports a single configuration file.
    94 currently a single Viper instance only supports a single configuration file.
    88 Viper does not default to any configuration search paths leaving defaults decision
    95 Viper does not default to any configuration search paths leaving defaults decision
    89 to an application.
    96 to an application.
    90 
    97 
    91 Here is an example of how to use Viper to search for and read a configuration file.
    98 Here is an example of how to use Viper to search for and read a configuration file.
    92 None of the specific paths are required, but at least one path should be provided
    99 None of the specific paths are required, but at least one path should be provided
    93 where a configuration file is expected.
   100 where a configuration file is expected.
    94 
   101 
    95 ```go
   102 ```go
    96 viper.SetConfigName("config") // name of config file (without extension)
   103 viper.SetConfigName("config") // name of config file (without extension)
       
   104 viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
    97 viper.AddConfigPath("/etc/appname/")   // path to look for the config file in
   105 viper.AddConfigPath("/etc/appname/")   // path to look for the config file in
    98 viper.AddConfigPath("$HOME/.appname")  // call multiple times to add many search paths
   106 viper.AddConfigPath("$HOME/.appname")  // call multiple times to add many search paths
    99 viper.AddConfigPath(".")               // optionally look for config in the working directory
   107 viper.AddConfigPath(".")               // optionally look for config in the working directory
   100 err := viper.ReadInConfig() // Find and read the config file
   108 err := viper.ReadInConfig() // Find and read the config file
   101 if err != nil { // Handle errors reading the config file
   109 if err != nil { // Handle errors reading the config file
   102 	panic(fmt.Errorf("Fatal error config file: %s \n", err))
   110 	panic(fmt.Errorf("Fatal error config file: %s \n", err))
   103 }
   111 }
       
   112 ```
       
   113 
       
   114 You can handle the specific case where no config file is found like this:
       
   115 
       
   116 ```go
       
   117 if err := viper.ReadInConfig(); err != nil {
       
   118     if _, ok := err.(viper.ConfigFileNotFoundError); ok {
       
   119         // Config file not found; ignore error if desired
       
   120     } else {
       
   121         // Config file was found but another error was produced
       
   122     }
       
   123 }
       
   124 
       
   125 // Config file found and successfully parsed
       
   126 ```
       
   127 
       
   128 *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`
       
   129 
       
   130 ### Writing Config Files
       
   131 
       
   132 Reading from config files is useful, but at times you want to store all modifications made at run time.
       
   133 For that, a bunch of commands are available, each with its own purpose:
       
   134 
       
   135 * 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.
       
   136 * 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.
       
   137 * WriteConfigAs - writes the current viper configuration to the given filepath. Will overwrite the given file, if it exists.
       
   138 * SafeWriteConfigAs - writes the current viper configuration to the given filepath. Will not overwrite the given file, if it exists.
       
   139 
       
   140 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.
       
   141 
       
   142 A small examples section:
       
   143 
       
   144 ```go
       
   145 viper.WriteConfig() // writes current config to predefined path set by 'viper.AddConfigPath()' and 'viper.SetConfigName'
       
   146 viper.SafeWriteConfig()
       
   147 viper.WriteConfigAs("/path/to/my/.config")
       
   148 viper.SafeWriteConfigAs("/path/to/my/.config") // will error since it has already been written
       
   149 viper.SafeWriteConfigAs("/path/to/my/.other_config")
   104 ```
   150 ```
   105 
   151 
   106 ### Watching and re-reading config files
   152 ### Watching and re-reading config files
   107 
   153 
   108 Viper supports the ability to have your application live read a config file while running.
   154 Viper supports the ability to have your application live read a config file while running.
   177 ```
   223 ```
   178 
   224 
   179 ### Working with Environment Variables
   225 ### Working with Environment Variables
   180 
   226 
   181 Viper has full support for environment variables. This enables 12 factor
   227 Viper has full support for environment variables. This enables 12 factor
   182 applications out of the box. There are four methods that exist to aid working
   228 applications out of the box. There are five methods that exist to aid working
   183 with ENV:
   229 with ENV:
   184 
   230 
   185  * `AutomaticEnv()`
   231  * `AutomaticEnv()`
   186  * `BindEnv(string...) : error`
   232  * `BindEnv(string...) : error`
   187  * `SetEnvPrefix(string)`
   233  * `SetEnvPrefix(string)`
   188  * `SetEnvKeyReplacer(string...) *strings.Replacer`
   234  * `SetEnvKeyReplacer(string...) *strings.Replacer`
       
   235  * `AllowEmptyEnv(bool)`
   189 
   236 
   190 _When working with ENV variables, it’s important to recognize that Viper
   237 _When working with ENV variables, it’s important to recognize that Viper
   191 treats ENV variables as case sensitive._
   238 treats ENV variables as case sensitive._
   192 
   239 
   193 Viper provides a mechanism to try to ensure that ENV variables are unique. By
   240 Viper provides a mechanism to try to ensure that ENV variables are unique. By
   196 prefix.
   243 prefix.
   197 
   244 
   198 `BindEnv` takes one or two parameters. The first parameter is the key name, the
   245 `BindEnv` takes one or two parameters. The first parameter is the key name, the
   199 second is the name of the environment variable. The name of the environment
   246 second is the name of the environment variable. The name of the environment
   200 variable is case sensitive. If the ENV variable name is not provided, then
   247 variable is case sensitive. If the ENV variable name is not provided, then
   201 Viper will automatically assume that the key name matches the ENV variable name,
   248 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),
   202 but the ENV variable is IN ALL CAPS. When you explicitly provide the ENV
   249 it **does not** automatically add the prefix. For example if the second parameter is "id",
   203 variable name, it **does not** automatically add the prefix.
   250 Viper will look for the ENV variable "ID".
   204 
   251 
   205 One important thing to recognize when working with ENV variables is that the
   252 One important thing to recognize when working with ENV variables is that the
   206 value will be read each time it is accessed. Viper does not fix the value when
   253 value will be read each time it is accessed. Viper does not fix the value when
   207 the `BindEnv` is called.
   254 the `BindEnv` is called.
   208 
   255 
   214 
   261 
   215 `SetEnvKeyReplacer` allows you to use a `strings.Replacer` object to rewrite Env
   262 `SetEnvKeyReplacer` allows you to use a `strings.Replacer` object to rewrite Env
   216 keys to an extent. This is useful if you want to use `-` or something in your
   263 keys to an extent. This is useful if you want to use `-` or something in your
   217 `Get()` calls, but want your environmental variables to use `_` delimiters. An
   264 `Get()` calls, but want your environmental variables to use `_` delimiters. An
   218 example of using it can be found in `viper_test.go`.
   265 example of using it can be found in `viper_test.go`.
       
   266 
       
   267 Alternatively, you can use `EnvKeyReplacer` with `NewWithOptions` factory function.
       
   268 Unlike `SetEnvKeyReplacer`, it accepts a `StringReplacer` interface allowing you to write custom string replacing logic.
       
   269 
       
   270 By default empty environment variables are considered unset and will fall back to
       
   271 the next configuration source. To treat empty environment variables as set, use
       
   272 the `AllowEmptyEnv` method.
   219 
   273 
   220 #### Env example
   274 #### Env example
   221 
   275 
   222 ```go
   276 ```go
   223 SetEnvPrefix("spf") // will be uppercased automatically
   277 SetEnvPrefix("spf") // will be uppercased automatically
   339 To enable remote support in Viper, do a blank import of the `viper/remote`
   393 To enable remote support in Viper, do a blank import of the `viper/remote`
   340 package:
   394 package:
   341 
   395 
   342 `import _ "github.com/spf13/viper/remote"`
   396 `import _ "github.com/spf13/viper/remote"`
   343 
   397 
   344 Viper will read a config string (as JSON, TOML, YAML or HCL) retrieved from a path
   398 Viper will read a config string (as JSON, TOML, YAML, HCL or envfile) retrieved from a path
   345 in a Key/Value store such as etcd or Consul.  These values take precedence over
   399 in a Key/Value store such as etcd or Consul.  These values take precedence over
   346 default values, but are overridden by configuration values retrieved from disk,
   400 default values, but are overridden by configuration values retrieved from disk,
   347 flags, or environment variables.
   401 flags, or environment variables.
   348 
   402 
   349 Viper uses [crypt](https://github.com/xordataexchange/crypt) to retrieve
   403 Viper uses [crypt](https://github.com/xordataexchange/crypt) to retrieve
   374 ### Remote Key/Value Store Example - Unencrypted
   428 ### Remote Key/Value Store Example - Unencrypted
   375 
   429 
   376 #### etcd
   430 #### etcd
   377 ```go
   431 ```go
   378 viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
   432 viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
   379 viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
   433 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"
   380 err := viper.ReadRemoteConfig()
   434 err := viper.ReadRemoteConfig()
   381 ```
   435 ```
   382 
   436 
   383 #### Consul
   437 #### Consul
   384 You need to set a key to Consul key/value storage with JSON value containing your desired config.  
   438 You need to set a key to Consul key/value storage with JSON value containing your desired config.  
   402 
   456 
   403 ### Remote Key/Value Store Example - Encrypted
   457 ### Remote Key/Value Store Example - Encrypted
   404 
   458 
   405 ```go
   459 ```go
   406 viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")
   460 viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")
   407 viper.SetConfigType("json") // because there is no file extension in a stream of bytes,  supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
   461 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"
   408 err := viper.ReadRemoteConfig()
   462 err := viper.ReadRemoteConfig()
   409 ```
   463 ```
   410 
   464 
   411 ### Watching Changes in etcd - Unencrypted
   465 ### Watching Changes in etcd - Unencrypted
   412 
   466 
   413 ```go
   467 ```go
   414 // alternatively, you can create a new viper instance.
   468 // alternatively, you can create a new viper instance.
   415 var runtime_viper = viper.New()
   469 var runtime_viper = viper.New()
   416 
   470 
   417 runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml")
   471 runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml")
   418 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"
   472 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"
   419 
   473 
   420 // read from remote config the first time.
   474 // read from remote config the first time.
   421 err := runtime_viper.ReadRemoteConfig()
   475 err := runtime_viper.ReadRemoteConfig()
   422 
   476 
   423 // unmarshal config
   477 // unmarshal config
   449 
   503 
   450  * `Get(key string) : interface{}`
   504  * `Get(key string) : interface{}`
   451  * `GetBool(key string) : bool`
   505  * `GetBool(key string) : bool`
   452  * `GetFloat64(key string) : float64`
   506  * `GetFloat64(key string) : float64`
   453  * `GetInt(key string) : int`
   507  * `GetInt(key string) : int`
       
   508  * `GetIntSlice(key string) : []int`
   454  * `GetString(key string) : string`
   509  * `GetString(key string) : string`
   455  * `GetStringMap(key string) : map[string]interface{}`
   510  * `GetStringMap(key string) : map[string]interface{}`
   456  * `GetStringMapString(key string) : map[string]string`
   511  * `GetStringMapString(key string) : map[string]string`
   457  * `GetStringSlice(key string) : []string`
   512  * `GetStringSlice(key string) : []string`
   458  * `GetTime(key string) : time.Time`
   513  * `GetTime(key string) : time.Time`
   604 	PathMap string `mapstructure:"path_map"`
   659 	PathMap string `mapstructure:"path_map"`
   605 }
   660 }
   606 
   661 
   607 var C config
   662 var C config
   608 
   663 
   609 err := Unmarshal(&C)
   664 err := viper.Unmarshal(&C)
   610 if err != nil {
   665 if err != nil {
   611 	t.Fatalf("unable to decode into struct, %v", err)
   666 	t.Fatalf("unable to decode into struct, %v", err)
   612 }
   667 }
   613 ```
   668 ```
   614 
   669 
       
   670 If you want to unmarshal configuration where the keys themselves contain dot (the default key delimiter),
       
   671 you have to change the delimiter:
       
   672 
       
   673 ```go
       
   674 v := viper.NewWithOptions(viper.KeyDelimiter("::"))
       
   675 
       
   676 v.SetDefault("chart::values", map[string]interface{}{
       
   677     "ingress": map[string]interface{}{
       
   678         "annotations": map[string]interface{}{
       
   679             "traefik.frontend.rule.type":                 "PathPrefix",
       
   680             "traefik.ingress.kubernetes.io/ssl-redirect": "true",
       
   681         },
       
   682     },
       
   683 })
       
   684 
       
   685 type config struct {
       
   686 	Chart struct{
       
   687         Values map[string]interface{}
       
   688     }
       
   689 }
       
   690 
       
   691 var C config
       
   692 
       
   693 v.Unmarshal(&C)
       
   694 ```
       
   695 
       
   696 Viper also supports unmarshaling into embedded structs:
       
   697 
       
   698 ```go
       
   699 /*
       
   700 Example config:
       
   701 
       
   702 module:
       
   703     enabled: true
       
   704     token: 89h3f98hbwf987h3f98wenf89ehf
       
   705 */
       
   706 type config struct {
       
   707 	Module struct {
       
   708 		Enabled bool
       
   709 
       
   710 		moduleConfig `mapstructure:",squash"`
       
   711 	}
       
   712 }
       
   713 
       
   714 // moduleConfig could be in a module specific package
       
   715 type moduleConfig struct {
       
   716 	Token string
       
   717 }
       
   718 
       
   719 var C config
       
   720 
       
   721 err := viper.Unmarshal(&C)
       
   722 if err != nil {
       
   723 	t.Fatalf("unable to decode into struct, %v", err)
       
   724 }
       
   725 ```
       
   726 
       
   727 Viper uses [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) under the hood for unmarshaling values which uses `mapstructure` tags by default.
       
   728 
   615 ### Marshalling to string
   729 ### Marshalling to string
   616 
   730 
   617 You may need to marhsal all the settings held in viper into a string rather than write them to a file. 
   731 You may need to marshal all the settings held in viper into a string rather than write them to a file. 
   618 You can use your favorite format's marshaller with the config returned by `AllSettings()`.
   732 You can use your favorite format's marshaller with the config returned by `AllSettings()`.
   619 
   733 
   620 ```go
   734 ```go
   621 import (
   735 import (
   622     yaml "gopkg.in/yaml.v2"
   736     yaml "gopkg.in/yaml.v2"
   623     // ...
   737     // ...
   624 ) 
   738 ) 
   625 
   739 
   626 func yamlStringSettings() string {
   740 func yamlStringSettings() string {
   627     c := viper.AllSettings()
   741     c := viper.AllSettings()
   628 	bs, err := yaml.Marshal(c)
   742     bs, err := yaml.Marshal(c)
   629 	if err != nil {
   743     if err != nil {
   630         t.Fatalf("unable to marshal config to YAML: %v", err)
   744         log.Fatalf("unable to marshal config to YAML: %v", err)
   631     }
   745     }
   632 	return string(bs)
   746     return string(bs)
   633 }
   747 }
   634 ```
   748 ```
   635 
   749 
   636 ## Viper or Vipers?
   750 ## Viper or Vipers?
   637 
   751 
   665 When working with multiple vipers, it is up to the user to keep track of the
   779 When working with multiple vipers, it is up to the user to keep track of the
   666 different vipers.
   780 different vipers.
   667 
   781 
   668 ## Q & A
   782 ## Q & A
   669 
   783 
   670 Q: Why not INI files?
       
   671 
       
   672 A: Ini files are pretty awful. There’s no standard format, and they are hard to
       
   673 validate. Viper is designed to work with JSON, TOML or YAML files. If someone
       
   674 really wants to add this feature, I’d be happy to merge it. It’s easy to specify
       
   675 which formats your application will permit.
       
   676 
       
   677 Q: Why is it called “Viper”?
   784 Q: Why is it called “Viper”?
   678 
   785 
   679 A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe))
   786 A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe))
   680 to [Cobra](https://github.com/spf13/cobra). While both can operate completely
   787 to [Cobra](https://github.com/spf13/cobra). While both can operate completely
   681 independently, together they make a powerful pair to handle much of your
   788 independently, together they make a powerful pair to handle much of your