Config
Manage your application config as a typesafe struct in as little as two function calls.
type MyConfig struct {
DatabaseUrl string `config:"DATABASE_URL"`
FeatureFlag bool `config:"FEATURE_FLAG"`
Port int // tags are optional. PORT is assumed
...
}
var c MyConfig
err := config.FromEnv().To(&c)
How It Works
It's just simple, pure stdlib.
-
A field's type determines what strconv function is called.
-
All string conversion rules are as defined in the strconv package
-
time.Duration
follows the same parsing rules as time.ParseDuration -
*net.URL
follows the same parsing rules as url.Parse- NOTE:
*net.URL
fields on the struct must be a pointer
- NOTE:
-
If chaining multiple data sources, data sets are merged. Later values override previous values.
config.From("dev.config").FromEnv().To(&c)
-
Unset values remain intact or as their native zero value
-
Nested structs/subconfigs are delimited with double underscore
- e.g.
PARENT__CHILD
- e.g.
-
Env vars map to struct fields case insensitively
- NOTE: Also true when using struct tags.
-
Any errors encountered are aggregated into a single error value
- the entirety of the struct is always attempted
- failed conversions (i.e. converting "x" to an int) and file i/o are the only sources of errors
- missing values are not errors
Why you should use this
- It's the cloud-native way to manage config. See 12 Factor Apps
- Simple:
- only 2 lines to configure.
- Composeable:
- Merge local files and environment variables for effortless local development.
- small:
- only stdlib
- < 180 LoC
Design Philosophy
Opinionated and narrow in scope. This library is only meant to do config binding. Feel free to use it on its own, or alongside other libraries.
-
Only structs at the entry point. This keeps the API surface small.
-
Slices are space delimited. This matches how environment variables and commandline args are handled by the
go
cmd. -
No slices of structs. The extra complexity isn't warranted for such a niche usecase.
-
No maps. The only feature of maps not handled by structs for this usecase is dynamic keys.
-
No pointer members. If you really need one, just take the address of parts of your struct.
- One exception is
*url.URL
, which is explicitly a pointer for ease of use, matching theurl
package conventions
- One exception is