Learn-skills.dev num30-config
Write, debug, and explain Go configuration code using the github.com/num30/config library. Use this skill when the user asks to set up config structs, read from files/env vars/CLI flags, validate config, watch for changes, or use the num30/config package in Go applications.
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/num30-config" ~/.claude/skills/neversight-learn-skills-dev-num30-config && rm -rf "$T"
manifest:
data/skills-md/aaronflorey/agent-skills/num30-config/SKILL.mdsource content
This skill provides comprehensive knowledge of num30/config (
github.com/num30/config), a declarative Go configuration library that reads config from YAML/JSON/TOML files, environment variables, and command-line flags in a single call.
Quick Reference
Install:
go get github.com/num30/config
Minimal usage:
import "github.com/num30/config" type Config struct { Host string `default:"localhost" validate:"required"` Port int `default:"8080"` } func main() { var cfg Config err := config.NewConfReader("myapp").Read(&cfg) if err != nil { panic(err) } }
Configuration Sources & Priority
Values are merged in this order (highest priority wins):
- Command-line flags (
)--host=localhost - Environment variables (
)HOST=localhost - Config file (
)myapp.yaml - Struct tag defaults (
)default:"localhost"
Struct Tags
| Tag | Purpose | Example |
|---|---|---|
| Default value | |
| Validation rule (go-playground/validator) | |
| Override CLI flag name | |
| Override env var name | |
| Flag usage/help text | |
| Squash embedded struct fields to parent level | see below |
ConfReader Builder API
config.NewConfReader("myapp") // create reader (config name = file name + env prefix base) .WithSearchDirs("/etc/conf", "./") // override config file search dirs (default: home + current dir) .WithPrefix("MYAPP") // prefix for env vars: MYAPP_DB_HOST .Read(&cfg) // read and populate struct (returns error)
Watch for live config changes:
reader := config.NewConfReader("myapp") err := reader.Read(&cfg) mutex := reader.Watch() // call AFTER Read(); panics if called before // thread-safe access: mutex.RLock() val := cfg.SomeField mutex.RUnlock()
Config File
- File name:
(or<configName>.yaml
,.json
,.toml
,.hcl
,.ini
,.env
).properties - Search order: home directory, then current directory (override with
)WithSearchDirs - Field name mapping: camelCase → lower camelCase YAML key
# For struct field DB.DbName: db: dbName: "mydb"
Environment Variables
- Default pattern:
with dots replaced byFIELD_PATH
, uppercased_
→App.Server.PortAPP_SERVER_PORT
- With prefix:
→NewConfReader("x").WithPrefix("MYAPP")MYAPP_APP_SERVER_PORT - Override with
tag:envvar
envvar:"DB_PASS"`Password string \
DB_PASS`→ reads from
Command-Line Flags
- Default pattern: lowercase dotted path with
prefix--
→App.Server.Port--app.server.port=8080
- Boolean flags: pass flag alone (no value needed):
--verbose - Override with
tag:flag
flag:"debug"`Debug bool \
--debug`→ - Slices: repeat the flag:
--slice a --slice b - Byte slices: base64-encoded:
--bytes dGVzdA==
Complete Example
package main import ( "fmt" "time" "github.com/num30/config" ) type Config struct { GlobalConfig `mapstructure:",squash"` // squash: fields promoted to top level Debug bool DB DatabaseConfig DefaultVal string `default:"default value"` Tags []string `default:"[\"a\",\"b\"]"` } type GlobalConfig struct { Verbose bool `flag:"verbose" usage:"enable verbose logging"` } type DatabaseConfig struct { Host string `default:"localhost" validate:"required"` Password string `validate:"required" envvar:"DB_PASS"` DbName string `default:"mydb"` Username string `default:"root"` Port int `default:"5432"` Timeout time.Duration `default:"30s"` } func main() { var cfg Config err := config.NewConfReader("myapp"). WithSearchDirs("/etc/myapp", "./"). WithPrefix("MYAPP"). Read(&cfg) if err != nil { panic(err) } fmt.Printf("%+v\n", cfg) }
Squash Embedding
Use
mapstructure:",squash" on an embedded struct to promote its fields to the parent level in config files and env vars:
type GlobalConfig struct { Verbose bool } type AppConfig struct { GlobalConfig `mapstructure:",squash"` // access as `verbose`, not `globalConfig.verbose` Name string }
Config file:
verbose: true (not globalConfig.verbose: true)
Env var: VERBOSE=true (not GLOBAL_CONFIG_VERBOSE=true)
Supported Go Types
All primitive types are supported as config fields:
bool, int/int8/int16/int32/int64, uint/uint8/uint16/uint32/uint64, float32/float64, string, []string, []byte (base64 in flags/env), time.Duration
Validation
Uses
go-playground/validator tags on struct fields:
type Config struct { Host string `validate:"required"` Port int `validate:"min=1,max=65535"` Email string `validate:"required,email"` }
Read() returns a validation error if constraints are violated. See validator docs for full tag list.
Built-in Config Structs (lib package)
import "github.com/num30/config/lib" type Config struct { DB lib.PostgresqlDb // provides Host, Password, DbName, Username, Port, SslEnabled with sane defaults } // Get connection string: connStr := cfg.DB.GetConnString() // → "host=localhost user=postgres password=pass database= port=5432 sslmode=disable"
lib.PostgresqlDb defaults: Host:"localhost", Password:"pass", Username:"postgres", Port:5432, SslEnabled:false
Slices
type Config struct { Slice []string }
| Source | Format |
|---|---|
| Env var | |
| Config file | |
| CLI flags | |
Error Handling
Read() returns errors for:
- Nil or non-pointer config struct
- Config file parse failures (
)"failed to unmarshal struct" - Default value failures (
)"failed to set default values" - Validation failures (
)"validation error: Key: '...' Error:..."
Watch() panics if called before Read().
Additional References
- references/api.md — Full API reference
- references/examples.md — Real-world usage examples