Fully Typed
Load[T] returns your exact struct — not map[string]interface{}. Types checked at compile time. No casting, no panics.
Load from YAML, env, JSON, TOML, Vault, AWS, or Kubernetes. Validate with struct tags. Redact secrets automatically. Get human-readable errors, not stack traces.
go get github.com/MimoJanra/confkit
Typed config with batteries included — validation, secrets, multi-source merging — without assembling multiple libraries by hand.
Load[T] returns your exact struct — not map[string]interface{}. Types checked at compile time. No casting, no panics.
Rules in struct tags: validate:"required,min=1,max=65535". No extra config files. Custom validators per load call. Cross-field validation.
Know which field failed, which rule, and which source. Explain(err) gives actionable messages, not cryptic stack traces.
Tag any field secret:"true". Automatically redacted in errors, dumps, and logs. No secrets ever leak. Audit trail available.
YAML, env, JSON, TOML, flags, Kubernetes, Vault, AWS — in explicit priority order. First source per field wins.
Only yaml.v3 + go-toml in core. Cloud integrations are optional modules — pull only what you need.
Define your struct once. Defaults and validation live in the tags.
go get github.com/MimoJanra/confkit
Annotate fields with env, default, validate, and secret tags.
confkit.Load[T](...)Pass sources in priority order. Get back your typed struct or a clear error.
Explain(err)One call gives a human-readable message safe to log.Fatal — secrets redacted.
type Config struct {
Host string `env:"HOST" default:"localhost"`
Port int `env:"PORT" default:"8080" validate:"min=1,max=65535"`
Timeout time.Duration `env:"TIMEOUT" default:"30s"`
DB struct {
DSN string `env:"DSN" validate:"required" secret:"true"`
MaxConns int `env:"MAX_CONNS" default:"10" validate:"min=1,max=100"`
} `prefix:"DB_"`
}
cfg, err := confkit.Load[Config](
confkit.FromFlags(),
confkit.FromEnv(),
confkit.FromYAML("config.yaml"),
)
if err != nil {
log.Fatal(confkit.Explain(err))
}type Config struct {
Server struct {
Addr string `env:"ADDR" default:":8080"`
TLS bool `env:"TLS" default:"false"`
}
Database struct {
URL string `env:"URL" validate:"required" secret:"true"`
MaxConns int `env:"MAX_CONNS" default:"10"`
}
}
cfg, err := confkit.Load[Config](confkit.FromEnv())
// SERVER_ADDR=:3000 // DATABASE_URL=postgres://user:pass@localhost/db // DATABASE_MAX_CONNS=20
type Config struct {
Verbose bool `flag:"verbose" short:"v"`
Output string `flag:"output" short:"o" default:"stdout"`
InputDir string `flag:"input" validate:"required"`
}
cfg, err := confkit.Load[Config](confkit.FromFlags())
// ./mytool -v -o report.txt --input /dataimport "github.com/MimoJanra/confkit/vault"
type Config struct {
API struct {
Key string `validate:"required" secret:"true"`
Secret string `validate:"required" secret:"true"`
}
}
auth := vault.VaultTokenAuth(os.Getenv("VAULT_TOKEN"))
cfg, err := confkit.Load[Config](
vault.FromVault("https://vault.example.com", auth, "/secret/myapp"),
)// Priority: env → env-specific YAML → defaults
cfg, err := confkit.Load[Config](
confkit.FromEnv(),
confkit.FromYAML("config."+os.Getenv("ENV")+".yaml"),
confkit.FromYAML("config.defaults.yaml"),
)
// ENV=prod → config.prod.yaml // ENV=dev → config.dev.yaml // Fallback: config.defaults.yaml
confkit gives you typed config with validation, defaults, and safe error messages — all from a single struct definition.
| Feature | confkit | Viper | envconfig | koanf |
|---|---|---|---|---|
Typed Load[T] | ✅ | ❌ | ⚠️ | ❌ |
| Defaults via struct tags | ✅ | ⚠️ | ✅ | ❌ |
| Built-in validation rules | ✅ | ❌ | ❌ | ❌ |
| Secret redaction | ✅ | ❌ | ❌ | ❌ |
| Multi-source merging | ✅ | ✅ | ⚠️ | ✅ |
| Lightweight core | ✅ | ❌ | ✅ | ✅ |
| Cloud integrations | optional modules | bundled | N/A | optional |
| Runtime hot reload | ✅ | ✅ | ❌ | ⚠️ |
you need heavy runtime reloading with watches across many files and don't need validation or type safety.
you only care about environment variables and simple type conversion — nothing else.
you want extreme modularity and don't need validation, secret redaction, or typed loading.
you want one struct for all config, built-in validation, safe error messages, and optional cloud sources.
Built-in sources cover the common cases. Cloud integrations are optional modules — each a separate go get.
Validation Rules
| Rule | Types | Behaviour |
|---|---|---|
required | any | Non-zero value required |
min=N | int, float | Value ≥ N |
min=N | string | Length ≥ N characters |
max=N | int, float | Value ≤ N |
max=N | string | Length ≤ N characters |
oneof=a b c | string | Must equal one of the options |
email | string | Valid email address |
http_url | string | Valid HTTP/HTTPS URL |
ip, ipv4, ipv6 | string | Valid IP address |
uuid | string | Valid UUID v1–v5 |
port | int, string | Valid port 1–65535 |
regex=pattern | string | Must match regexp |
Rules are comma-separated: validate:"required,min=1,max=65535"
Struct Tag Reference