• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.github/H03-May-2022-

internal/testutil/H25-Jun-2021-

remote/H25-Jun-2021-

.editorconfigH A D25-Jun-2021213

.gitignoreH A D25-Jun-202137

.golangci.ymlH A D25-Jun-20211.8 KiB

LICENSEH A D25-Jun-20211.1 KiB

MakefileH A D25-Jun-20212.5 KiB

README.mdH A D25-Jun-202127.1 KiB

TROUBLESHOOTING.mdH A D25-Jun-20211.4 KiB

flags.goH A D25-Jun-20211.3 KiB

flags_test.goH A D25-Jun-20211.3 KiB

go.modH A D25-Jun-2021587

go.sumH A D25-Jun-202160.9 KiB

overrides_test.goH A D25-Jun-20216.3 KiB

util.goH A D25-Jun-20215.4 KiB

util_test.goH A D25-Jun-20212.1 KiB

viper.goH A D25-Jun-202160.7 KiB

viper_test.goH A D25-Jun-202153 KiB

watch.goH A D25-Jun-2021172

watch_wasm.goH A D25-Jun-2021431

README.md

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