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 |