Post

Go config: many good pieces, no whole picture

Why nested Go config needs an explicit map-in-the-middle — and how go-config addresses merge, normalisation, and symmetric codecs.

Go config: many good pieces, no whole picture

Published: Medium — 2026-05-02 · 8 min read
Repository: github.com/eSlider/go-config

Thesis

Go has strong config libraries — Viper, Koanf, envconfig, godotenv, format parsers, mapstructure — but most optimise for one slice of the problem. Production services need three jobs at once:

  1. Parse a format (YAML, JSON, INI, dotenv)
  2. Compose layers with predictable precedence (defaults → file → local → env)
  3. Decode into a typed Config struct with sane key aliasing

Nested structs, embedded fields, and cross-format key names (sub-service vs SUB_SERVICE) are where the seams show.

“Map in the middle”

The pattern that keeps working:

1
bytes → nested map[string]any → mapstructure → struct

Parsers own the left arrow; mapstructure owns the right. The middle — canonical nested maps, deep merge, key normalisation — is what teams reinvent in every repo.

Where go-config fits

go-config targets that middle layer with symmetric codecs across env / yaml / json / ini, deep merge, LowerAlnum normalisation, and envc CLI for convert / get / merge. Design scope and breaking changes from v0.1.0 are documented in the repo ASR index.

Not a benchmark shoot-out — a map of ecosystem trade-offs (Viper env binding, Koanf composability, env-first loaders) and a concrete library answer.

This post is licensed under CC BY 4.0 by the author.