Learn-skills.dev go-viper
Write, debug, and explain Go configuration code using github.com/spf13/viper. Use this skill whenever the user wants Viper-based config loading, config structs, file plus env plus flag precedence, Cobra or pflag integration, unmarshaling config into structs, env key replacers, or a clean application config bootstrap that follows Viper's README behavior.
install
source · Clone the upstream repo
git clone https://github.com/NeverSight/learn-skills.dev
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/NeverSight/learn-skills.dev "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/skills-md/aaronflorey/agent-skills/go-viper" ~/.claude/skills/neversight-learn-skills-dev-go-viper && rm -rf "$T"
manifest:
data/skills-md/aaronflorey/agent-skills/go-viper/SKILL.mdsource content
Use this skill to produce a clean Viper setup that reads configuration from file, flags, and environment with Viper's normal precedence:
- explicit
Set - flags
- environment variables
- config file
- remote key/value store
- defaults
Core approach
- Prefer
over the package global; build one configured instance and pass it where needed.viper.New() - Define a typed
struct and unmarshal into it after all defaults, file paths, env bindings, and flag bindings are configured.Config - Keep configuration bootstrap in one place such as
orinternal/config
with apkg/config
function.Load(...) - Treat the config file as optional only when the app design allows it; otherwise return a clear error.
- Bind flags and env explicitly for important keys, and use
plus an env key replacer for the general case.AutomaticEnv()
Clean Viper bootstrap
When writing a Viper-based loader, follow this order:
- Create an instance with
.v := viper.New() - Set config file name, type if needed, and search paths.
- Set defaults with
.SetDefault - Configure env loading with
,SetEnvPrefix
,SetEnvKeyReplacer
, andAutomaticEnv
for special keys.BindEnv - Define and parse
or Cobra flags, then bind them withpflag
orBindPFlag
.BindPFlags - Call
.ReadInConfig() - Handle
separately from parse errors when the file is optional.viper.ConfigFileNotFoundError - Call
into a typed struct.Unmarshal(&cfg) - Validate the resulting struct if the app has required fields or constraints.
Implementation rules
- Use
tags on struct fields when file keys differ from Go field names.mapstructure - For nested keys that should map to env vars, use
withstrings.NewReplacer(".", "_", "-", "_")
.SetEnvKeyReplacer - Remember that env vars are case-sensitive and are read when accessed, not cached at bind time.
- Remember that Viper does not deep-merge complex values; later sources replace the whole value.
- Add all config paths before
and beforeReadInConfig()
.WatchConfig() - If the user uses Cobra, bind command flags directly from the command's flag set.
- If the user wants testable code, return both the typed config and the configured
only when the caller truly needs both; otherwise return just the typed config.*viper.Viper
Output expectations
- Give a small, production-leaning config package, not scattered snippets.
- Show how file, env, and flags work together in one example.
- Make precedence explicit in the explanation.
- Mention the exact env var names and flag names generated or bound.
References
- Read
for the recommended package shape, loader order, validation strategy, testing guidance, and common pitfalls.references/clean-config-pattern.md - Read
when the task is specifically about how file, env, and flags interact or why one source wins over another.references/file-env-flag-precedence.md - Read
for a compact end-to-end loader example.examples/clean_setup.go