cfgload
A lightweight Go library for loading application configuration from YAML files, with support for struct-tag defaults and file-based secrets.
The intent of this library is for use with Docker images, where a config file can be mounted at runtime and secrets can be injected as files. It provides a simple API for loading configuration into user-defined structs, with a clear loading order and minimal dependencies, reducing any setup code, and avoiding the need for callers to manage multiple config sources themselves.
As a design decisions, the library attempts to avoid ENV parameters as much as possible, which can be difficult to manage. Instead, it focuses on YAML files for both config and secrets, which can be easily mounted as volumes.
The only ENV parameters are for specifying the config and secrets file locations (which are defaulted anyway, and so are present only for flexibility), and an optional ENV variable for environment-specific config if needed (again, this is optional and the library will work without it).
How it works
Configuration is loaded in three layers, each overriding the previous:
- Struct defaults — via
default:"..." struct tags (using creasty/defaults)
- YAML file — from
./config/config.yaml by default, or the path in CONFIG_LOCATION
- Secrets — YAML key-value files in
SECRETS_LOCATION, named after their target struct path
Usage
Define a struct matching your YAML structure and call config.Initialise:
import "github.com/icarianflight/cfgload"
type AppConfig struct {
Debug bool `yaml:"debug"`
DB struct {
Host string `yaml:"host" default:"localhost"`
Port int `yaml:"port" default:"5432"`
User string `yaml:"user"`
Password string `yaml:"password"`
} `yaml:"db"`
}
cfg, err := cfgload.Initialise[AppConfig]()
Environment variables
| Variable |
Required |
Description |
ENV |
No |
Environment name (e.g. DEV, TEST, PROD) |
CONFIG_LOCATION |
No |
Path to YAML config file. Defaults to ./config/config.yaml |
SECRETS_LOCATION |
No |
Path to directory containing .secret files |
Secrets
Place .secret files in SECRETS_LOCATION. The filename (without extension) is a dot-separated path into the config struct, matched against yaml tags:
| File |
Target struct |
db.secret |
top-level db struct |
db.ssl.secret |
ssl sub-struct inside db |
Each file contains YAML key-value pairs:
# db.secret
user: mydbuser
password: s3cr3t
Loading sequence
sequenceDiagram
participant A as Application
participant C as config.Initialise[T]
participant D as creasty/defaults
participant F as YAML File
participant S as Secrets Files
A->>+C: config.Initialise[AppConfig]()
C->>+D: defaults.Set(&cfg)
D-->>-C: struct defaults applied
C->>+F: os.ReadFile(CONFIG_LOCATION)
F-->>-C: YAML bytes
C->>C: yaml.Unmarshal → cfg
opt SECRETS_LOCATION is set
loop each *.secret file
C->>+S: os.ReadFile(filename)
S-->>-C: YAML bytes
C->>C: navigateToField(path) + yaml.Unmarshal → sub-struct
end
end
C-->>-A: cfg, err