Automatically map environment variables into Go structs using reflection and tag-based mapping, with optional .env file support. Designed for modern Go services that need fast, declarative, zero-dependency configuration loading. It includes automatic SNAKE_CASE conversion, support for JSON and env tags, embedded structs, custom logging, prefix handling, field ignoring, and even parsing of slices and common data types—all without external libraries.
go get go.g3deon.com/autoenvimport "go.g3deon.com/autoenv"
type Config struct {
Port int `json:"port"`
Debug bool `json:"debug"`
Host string `json:"host"`
}
func main() {
cfg := &Config{}
autoenv.Load(cfg)
}By default, the library uses JSON tags and converts them to SNAKE_CASE:
type Config struct {
DatabaseURL string `json:"databaseUrl"` // Will look for DATABASE_URL
MaxRetries int `json:"maxRetries"` // Will look for MAX_RETRIES
}Use env tags for custom environment variable names:
type Config struct {
Port int `env:"SERVICE_PORT"` // Will look for SERVICE_PORT exactly
Debug bool `env:"APP_DEBUG"` // Will look for APP_DEBUG exactly
}- string
- Value is used as-is.
- bool
- Accepts standard boolean strings (true/false, 1/0, t/f, yes/no).
- Integers: int, int8, int16, int32, int64
- Parsed in base 10.
- time.Duration (as int64 underlying) is supported via string parsing with time.ParseDuration syntax (e.g., "150ms", "2s", "1h45m").
- Unsigned integers: uint, uint8, uint16, uint32, uint64
- Parsed in base 10.
- Floats: float32, float64
- Parsed as decimal numbers (e.g., "3.14").
- time.Time
- Parsed using RFC3339 format (e.g., "2024-01-02T15:04:05Z07:00").
- Slices of supported scalar types
- Comma-separated values; each element parsed according to its type.
- Whitespace around elements is trimmed.
- Examples:
- []string: "a,b,c"
- []int: "1,2,3"
- []bool: "true,false,true"
- []float64: "1.1, 2.2, 3.3"
- []time.Duration: "500ms, 2s, 1m"
- Pointers to any supported type
- Automatically allocated when a value is provided.
- Nested/embedded structs
- Recursively traversed; field names are flattened using underscore between levels (also combined with prefix and tags as described below).
- Only exported struct fields are considered.
- If configured to use only env tags, fields without env tags are ignored.
- Unsupported kinds (e.g., maps, complex numbers, arbitrary structs other than time.Time) are not set and will result in an error during parsing.
Add a prefix to all environment variables:
Add a prefix to all environment variables:
autoenv.Load(cfg, autoenv.WithPrefix("APP"))With the above configuration:
Portwill look forAPP_PORTDebugwill look forAPP_DEBUG
The library supports slices of basic types:
type Config struct {
Ports []int `json:"ports"` // PORTS=8080,8081,8082
Hosts []string `json:"hosts"` // HOSTS=localhost,127.0.0.1
Flags []bool `json:"flags"` // FLAGS=true,false,true
Numbers []float64 `json:"numbers"` // NUMBERS=1.1,2.2,3.3
}type DatabaseConfig struct {
Host string `json:"host"` // DATABASE_HOST
Port int `json:"port"` // DATABASE_PORT
Password string `json:"password"` // DATABASE_PASSWORD
}
type Config struct {
Database DatabaseConfig
AppName string `json:"appName"` // APP_NAME
}type Logger interface {
DebugF(format string, args ...any)
ErrorF(format string, args ...any)
// ...
}
// Implement your own logger type MyLogger struct{}
func (l *MyLogger) DebugF(format string, args ...any) {
log.Printf("[DEBUG] "+format, args...)
}
func (l *MyLogger) ErrorF(format string, args ...any) {
log.Printf("[ERROR] "+format, args...)
}
// Use your logger
autoenv.Load(cfg, autoenv.WithLogger(&MyLogger{}))MIT © 2025 G3deon, Inc.