// Package config provides a generic environment-variable + .env configuration // loader. Each application defines its own configuration struct (with // `env:"..."` tags) and calls Load to populate it. The framework owns only the // loading mechanism, never the schema — so the two apps can have completely // different configuration structs while sharing this loader. package config import ( "os" "github.com/caarlos0/env/v11" "github.com/joho/godotenv" ) // Load populates dst from the process environment. A ".env" file in the working // directory is loaded implicitly when present; passing a non-empty overrideFile // (e.g. from a --env-file flag) loads that file instead. In either case godotenv // never overwrites a variable already set in the real environment, so actual // environment variables always take precedence over the file. // // Load returns an error rather than exiting; callers (typically a thin app-side // wrapper) decide how to handle failure. func Load[T any](overrideFile string, dst *T) error { switch { case overrideFile != "": // Explicit override: the file is required, so a missing/unreadable file // is an error. if err := godotenv.Load(overrideFile); err != nil { return err } default: // Implicitly load ".env" when it exists. Its absence is not an error — // the process environment may already carry everything. if _, err := os.Stat(".env"); err == nil { if err := godotenv.Load(".env"); err != nil { return err } } } return env.Parse(dst) }