Skip to content

FlexConf

Flexible configuration & secret management for Go โ€” declare your config as plain Go types, and let the people who write the config decide where each value comes from: a file, an environment variable, or a vault. โœจ

service: api
timeout: 10s
url: https://$(env:HOST)/api            # ๐ŸŒฑ from the environment
token: $(secret:artifactory/token)      # ๐Ÿ” from an encrypted vault

Your application code never changes โ€” it just sees a string.

๐Ÿค” Why FlexConf?

Most config libraries make the application decide what is an env var, what is a flag, and what is a secret โ€” hardcoded at compile time. FlexConf flips that around:

The core idea

The application declares what configuration it needs (typed Go structs). The operator decides where each value comes from โ€” plain YAML, $(env:โ€ฆ), $(file:โ€ฆ), or $(secret:โ€ฆ) โ€” without touching a line of Go.

That separation is what makes the same binary run unchanged on a laptop, in CI, and in production โ€” only the config files differ.

โš™ How it works

flowchart LR
    A["๐Ÿ“ Config layers<br/><small>/etc/myapp โ†’ ./config</small>"] --> B["๐Ÿ”€ Deep merge"]
    B --> C["๐Ÿงฉ Resolve tokens<br/><small>env ยท file ยท config ยท secret</small>"]
    C --> D["๐Ÿท๏ธ Bind to Go struct<br/><small>typed, validated, all-or-nothing</small>"]
    C -.-> E["๐Ÿ” Vault agent<br/><small>ssh-agent-style, auto-locks</small>"]
  1. Layer โ€” config directories are merged lowest โ†’ highest precedence.
  2. Resolve โ€” $(scheme:path) tokens are expanded at load time.
  3. Bind โ€” the merged tree is bound to your struct; on any error, your struct is left untouched.

๐Ÿ“ฆ What's in the box

  • Layered configuration


    Stack config directories (/etc/myapp, ./config, โ€ฆ). Maps deep-merge, scalars override โ€” defaults live in Go.

  • Typed schema & binding


    Plain Go structs with flexconf tags. Required fields, durations, nested types โ€” binding is all-or-nothing.

  • Templating tokens


    $(env:โ€ฆ), $(file:โ€ฆ), $(config:โ€ฆ), $(secret:โ€ฆ) โ€” embeddable in literal text, with escaping and custom resolvers.

  • Vault-backed secrets


    Secrets live in an encrypted vault (KeePass, โ€ฆ), never in config files. Operators own the vault registry.

  • Secret agent & CLI


    flexconf secret unlock spawns an ssh-agent-style daemon holding the unlocked vault in memory, auto-locking on idle.

  • Variants & prompting


    Polymorphic config via discriminators, and interactive prompting when a value can't be resolved silently.

๐Ÿš€ Try it in 30 seconds

$ go get github.com/sylvanld/go-flexconf
type Config struct {
    Service string `flexconf:"service,required"`
    Token   string `flexconf:"token"` // may be $(secret:โ€ฆ) โ€” the type doesn't care
}

var cfg Config
err := flexconf.New("/etc/myapp", "./config").Load("config.yaml", &cfg)

That's it โ€” head to the Get started guide for the full four-step setup, including secrets. ๐Ÿ‘ˆ