A no-bullshit, thread-safe configuration library for Go that doesn't make you wanna punch your monitor. Tired of writing the same boring-ass env var parsing shit over and over? This badass package's got your back with reflection magic that actually works without making you cry.
This ain't your granddad's config parser. Here's what makes this package fucking legendary:
- Basic Types:
string,bool- the bread and butter - Signed Integers:
int,int8,int16,int32,int64- all the flavors you need - Unsigned Integers:
uint,uint8,uint16,uint32,uint64- for when you don't do negative vibes - Floating Point:
float32,float64- because math is hard - Time Durations:
time.Duration- parsed with Go's native format ("5s","10m","1h30m") - String Slices:
[]string- comma-separated values that get split automagically ("val1,val2,val3")
- Thread-Safe: Won't shit the bed under concurrent load
- Default Values: Set fallbacks so your app doesn't break when someone forgets to set an env var
- Minimal Dependencies: Just stdlib and one error handling package because we're not monsters
- Reflection-Based: Uses Go's reflection to automagically map env vars to struct fields
- Type Safety: Validates types and gives you proper error messages instead of cryptic bullshit
go get github.com/psyb0t/gonfigurationpackage main
import (
"fmt"
"log"
"os"
"time"
"github.com/psyb0t/gonfiguration"
)
type AppConfig struct {
// Basic types
ListenAddress string `env:"LISTEN_ADDRESS"`
Debug bool `env:"DEBUG"`
Port int `env:"PORT"`
// Advanced types
Timeout time.Duration `env:"TIMEOUT"`
AllowedHosts []string `env:"ALLOWED_HOSTS"`
// Database shit
DBDSN string `env:"DB_DSN"`
DBName string `env:"DB_NAME"`
DBUser string `env:"DB_USER"`
DBPass string `env:"DB_PASS"`
}
func main() {
cfg := AppConfig{}
// Set some defaults because you're not a savage
gonfiguration.SetDefaults(map[string]interface{}{
"LISTEN_ADDRESS": "127.0.0.1:8080",
"DEBUG": false,
"PORT": 8080,
"TIMEOUT": 30 * time.Second,
"ALLOWED_HOSTS": []string{"localhost", "127.0.0.1"},
"DB_DSN": "postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable",
})
// Set some env vars (in real life these come from your environment)
os.Setenv("DB_NAME", "myapp")
os.Setenv("DB_USER", "postgres-user")
os.Setenv("DB_PASS", "super-secret-password")
os.Setenv("DEBUG", "true")
os.Setenv("ALLOWED_HOSTS", "api.example.com, cdn.example.com, *.example.com")
// Parse that shit
if err := gonfiguration.Parse(&cfg); err != nil {
log.Fatalf("holy fuque! config parsing failed: %v", err)
}
fmt.Printf("Config loaded: %+v\n", cfg)
fmt.Printf("Allowed hosts: %v\n", cfg.AllowedHosts) // ["api.example.com", "cdn.example.com", "*.example.com"]
fmt.Printf("Timeout: %v\n", cfg.Timeout) // 30s
}The main function that does all the magic. Pass a pointer to your config struct and it'll populate it with env vars.
cfg := MyConfig{}
err := gonfiguration.Parse(&cfg)Set a single default value for when the env var doesn't exist.
gonfiguration.SetDefault("PORT", 8080)
gonfiguration.SetDefault("DEBUG", false)
gonfiguration.SetDefault("TIMEOUT", 30*time.Second)Set multiple defaults at once because batch operations are cooler.
gonfiguration.SetDefaults(map[string]interface{}{
"PORT": 8080,
"DEBUG": false,
"TIMEOUT": 30*time.Second,
"HOSTS": []string{"localhost", "127.0.0.1"}, // for []string fields
})Get all the default values you've set. Useful for debugging or just being nosy.
defaults := gonfiguration.GetDefaults()
fmt.Printf("All defaults: %+v\n", defaults)Get all the environment variables that were processed. Again, useful for debugging.
envVars := gonfiguration.GetEnvVars()
fmt.Printf("Processed env vars: %+v\n", envVars)Get everything - defaults merged with env vars. Env vars override defaults because that's how the world works.
allValues := gonfiguration.GetAllValues()
fmt.Printf("All config values: %+v\n", allValues)Nuke everything and start fresh. Clears all defaults and cached env vars.
gonfiguration.Reset() // Back to square oneThe library returns descriptive errors when things fuck up:
// Invalid struct (not a pointer)
err := gonfiguration.Parse(cfg) // Missing &
// Error: "yo, the destination ain't a pointer"
// Invalid target (not a struct)
str := "not a struct"
err := gonfiguration.Parse(&str)
// Error: "what the hell? expected a struct, but this ain't one"
// Type mismatch in defaults
gonfiguration.SetDefault("PORT", "not a number") // PORT field is int
cfg := Config{}
err := gonfiguration.Parse(&cfg)
// Error: "wtf.. Default value type mismatch"
// Invalid env var value
os.Setenv("PORT", "not-a-number")
err := gonfiguration.Parse(&cfg)
// Error: "wtf.. Failed to parse int: ..."This package is thread-safe using sync.RWMutex. You can safely:
- Call
Parse()from multiple goroutines - Set defaults concurrently
- Get values from different goroutines
// This won't blow up your app
go func() {
gonfiguration.SetDefault("KEY1", "value1")
}()
go func() {
gonfiguration.SetDefault("KEY2", "value2")
}()
go func() {
cfg := MyConfig{}
gonfiguration.Parse(&cfg)
}()- Struct fields MUST have
env:"ENV_VAR_NAME"tags - no tag, no parsing - Only supports simple structs - no nested structs, no complex types, no maps
- Pass a pointer to
Parse()- not the struct itself, you savage - String slices use comma separation -
"val1,val2,val3"becomes["val1", "val2", "val3"] - Time durations use Go format -
"30s","5m","2h30m", etc. - Empty string slices become empty slices -
""becomes[]string{} - Default value types must match field types - don't be an idiot
Copyright 2023-2025 Ciprian Mandache (ciprian.51k.eu)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.