Documentation
¶
Overview ¶
Package gonfig provides type-safe configuration loading from environment variables with support for defaults, secret masking, nested structs, and .env files.
The library uses struct tags to control configuration loading:
- `env` tag: Maps struct fields to environment variables
- `secret` tag: Maps struct fields to environment variables but masks them in output
- `default` tag: Provides fallback values when environment variables are not set
- `required` tag: Makes fields required (fails if not set and no default)
Supported types: string, bool, int (all sizes), float32, float64, slices, nested structs, time.Duration, time.Time, slog.Level, big.Int, decimal.Decimal, url.URL, net.IP, mail.Address, uuid.UUID, resource.Quantity, rsa.PrivateKey, ecdsa.PrivateKey (from PEM), vm.Program (expr-lang/expr), and any type implementing encoding.TextUnmarshaler
New: Nested structs (value or pointer) are fully supported with recursive processing.
Example usage:
type Config struct {
Port int `env:"PORT" default:"8080"`
APIKey string `secret:"API_KEY" required:"true"`
DB struct {
Host string `env:"DB_HOST" default:"localhost"`
Port int `env:"DB_PORT" default:"5432"`
}
// PostgreSQL URLs - supports both TCP and Unix socket formats
DatabaseURL url.URL `env:"DATABASE_URL" default:"postgres://user:pass@localhost:5432/mydb"`
SocketURL url.URL `env:"SOCKET_URL" default:"postgresql://user:pass@/mydb?host=/var/run/postgresql"`
}
cfg, err := gonfig.Load(Config{})
if err != nil {
log.Fatal(err)
}
log.Info("config loaded", "cfg", gonfig.PrettyString(cfg))
Package gonfig provides a small, type-safe configuration loader for Go application// // Crypto keys (PEM format)
PrivateKey rsa.PrivateKey `secret:"PRIVATE_KEY"` // Expression language for business rules AccessRule *vm.Program `env:"ACCESS_RULE" default:"user.role == 'admin'"` Rules []*vm.Program `env:"BUSINESS_RULES"` // Database URLs with support for both TCP and Unix sockets/
Features ¶
- Loads struct-tagged settings directly from environment variables
- Optional .env file support
- Default values and CSV slices parsing
- Extended parsing for time.Duration, uuid.UUID, decimal.Decimal, vm.Program (expr), and other specialized types
- Secret masking for sensitive configuration values
- Support for nested structs (both value and pointer types)
- Comprehensive type support including crypto keys, network addresses, and Kubernetes resource quantities
Supported Types ¶
The library supports a wide range of Go types:
- Basic types: string, bool, int (all sizes), float32, float64
- Collections: slices of supported types
- Time types: time.Duration, time.Time
- Network types: net.IP, mail.Address, url.URL
- Crypto types: rsa.PrivateKey, ecdsa.PrivateKey (from PEM format)
- Specialized types: uuid.UUID, decimal.Decimal, big.Int, slog.Level
- Kubernetes types: resource.Quantity
- Expression language: vm.Program (expr-lang/expr for business rules and validation)
- Any type implementing encoding.TextUnmarshaler
- Nested structs (recursive processing)
Struct Tags ¶
Configuration is controlled through struct tags:
- `env:"VAR_NAME"` - Maps field to environment variable
- `secret:"VAR_NAME"` - Maps field to environment variable but masks it in output
- `default:"value"` - Provides fallback value when environment variable is not set
- `required:"true"` - Makes field required (fails if not set and no default)
Quick Start ¶
package main
import (
"fmt"
"log"
"github.com/vivaneiona/gonfig"
)
type Config struct {
Port int `env:"PORT" default:"8080"`
Host string `env:"HOST" default:"localhost"`
Debug bool `env:"DEBUG" default:"false"`
APIKey string `secret:"API_KEY"`
Tags []string `env:"TAGS" default:"web,api"`
Database struct {
Host string `env:"DB_HOST" default:"localhost"`
Port int `env:"DB_PORT" default:"5432"`
}
DatabaseURL url.URL `env:"DATABASE_URL"`
}
func main() {
cfg, err := gonfig.Load(Config{})
if err != nil {
log.Fatal(err)
}
fmt.Println(gonfig.PrettyString(cfg)) // secrets are masked
}
Advanced Usage ¶
The library supports complex configuration scenarios:
type AdvancedConfig struct {
// Kubernetes resource quantities
DefaultMem resource.Quantity `env:"DEFAULT_MEM" default:"1Gi"`
DefaultDisk resource.Quantity `env:"DEFAULT_DISK" default:"10G"`
// Network configuration
IPAddress net.IP `env:"IP_ADDRESS"`
EmailAddr mail.Address `env:"EMAIL_ADDR"`
// Logging
LogLevel slog.Level `env:"LOG_LEVEL"`
// Crypto keys (PEM format)
PrivateKey rsa.PrivateKey `secret:"PRIVATE_KEY"`
// Database URLs with support for both TCP and Unix sockets
DatabaseURL url.URL `env:"DATABASE_URL" default:"postgres://user:pass@localhost:5432/mydb"`
SocketURL url.URL `env:"SOCKET_URL" default:"postgresql://user:pass@/mydb?host=/var/run/postgresql"`
}
Environment File Support ¶
Load configuration with optional .env file support:
cfg, err := gonfig.LoadWithDotenv(Config{}, ".env", ".env.local")
if err != nil {
log.Fatal(err)
}
API Reference ¶
The package provides three main functions:
func Load[T any](cfg T) (T, error) // Load from environment variables only func LoadWithDotenv[T any](cfg T, paths ...string) (T, error) // Load with .env file support func PrettyString(v any) string // Format config with masked secrets
Error Handling ¶
The library provides detailed error messages for configuration issues:
- Missing required fields
- Type conversion failures
- Invalid default values
- Malformed PEM keys or other specialized formats
All errors include context about the field name and expected format to aid in debugging.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Load ¶
Load populates a configuration struct from environment variables using reflection. Now supports nested structs (value or pointer) with recursive processing. It supports the following struct tags:
- `env:"ENV_VAR"`: Maps the field to the specified environment variable
- `secret:"SECRET_VAR"`: Maps the field to the specified environment variable (for secrets)
- `default:"value"`: Sets a default value if the environment variable is not set
- `required:"true"`: Makes the field required (fails if not set and no default)
Supported field types:
- string
- bool (parsed using strconv.ParseBool)
- int, int8, int16, int32, int64 (parsed using strconv.ParseInt)
- float32, float64 (parsed using strconv.ParseFloat)
- slices of the above types (comma-separated values)
- nested structs (value or pointer)
- time.Duration for int64 fields (when value ends with 's', 'ms', etc.)
- time.Duration (parsed using time.ParseDuration)
- time.Time (RFC3339 format or Unix seconds)
- log/slog.Level (debug|info|warn|error or integer)
- math/big.Int (base-10 integer strings)
- github.com/shopspring/decimal.Decimal (exact decimal arithmetic)
- url.URL (parsed using url.Parse, supports TCP and Unix socket PostgreSQL URLs) Examples: postgres://user:pass@host:port/db, postgresql://user:pass@/db?host=/socket/path
- net.IP (IPv4 and IPv6 addresses)
- net/mail.Address (email addresses with optional display names)
- github.com/google/uuid.UUID (UUID strings)
- k8s.io/apimachinery/pkg/api/resource.Quantity (Kubernetes resource units like 250m, 1.5Gi)
- crypto/rsa.PrivateKey (RSA private keys from PEM format)
- crypto/ecdsa.PrivateKey (ECDSA private keys from PEM format)
- github.com/expr-lang/expr/vm.Program (compiled expressions for business rules and validation)
- Any type implementing encoding.TextUnmarshaler
The function returns an error if:
- An unsupported field type is encountered
- A required field is missing
- Type conversion fails
Example:
type Config struct {
Port int `env:"PORT" default:"8080"`
Debug bool `env:"DEBUG" default:"false"`
APIKey string `secret:"API_KEY" required:"true"`
DB struct {
Host string `env:"DB_HOST" default:"localhost"`
}
}
cfg, err := Load(Config{})
if err != nil {
log.Fatal(err)
}
func LoadWithDotenv ¶
LoadWithDotenv loads configuration from environment variables with support for .env files. It first attempts to load a .env file using godotenv, then calls Load to populate the configuration struct from environment variables.
The function loads environment variables in this precedence order:
- Existing environment variables (highest priority)
- Variables from .env file
- Default values from struct tags (lowest priority)
If the .env file doesn't exist or can't be loaded, the error is silently ignored and the function continues with existing environment variables.
Parameters:
- config: Pointer to a configuration struct with tagged fields
- dotenvPath: Optional path to .env file (defaults to ".env" in current directory)
Example:
type Config struct {
Port int `env:"PORT" default:"8080"`
APIKey string `secret:"API_KEY"`
}
cfg := &Config{}
loaded := LoadWithDotenv(cfg, "config/.env")
LoadWithDotenv loads a .env file first, then calls Load to populate the configuration. It accepts an optional path to the .env file; if not provided, it defaults to ".env". Returns the populated configuration struct and any error encountered.
Example:
cfg, err := LoadWithDotenv(Config{}, ".env")
if err != nil {
log.Fatal(err)
}
func PrettyString ¶
PrettyString returns a JSON-formatted string representation of the configuration with secret fields automatically masked for safe logging and debugging. Now supports nested structs (value or pointer) with recursive processing.
Fields tagged with `secret` will have their values masked using the mask function. The function uses struct tags to determine field names in the output:
- `env` tag value is used as the key name
- `secret` tag value is used as the key name (and value is masked)
- If no tag is present, the struct field name is used
Example:
type Config struct {
Port int `env:"PORT"`
APIKey string `secret:"API_KEY"`
DB struct {
Host string `env:"DB_HOST"`
}
// cfg := &Config{Port: 8080, APIKey: "secret123"}
fmt.Println(PrettyString(cfg))
// Output: {"PORT": 8080, "API_KEY": "sec*****", "DB": {"DB_HOST": ""}}
func RegisterParser ¶
RegisterParser lets users plug in custom type parsers. Call this in your init() or main() before Load.
func RegisterParserFactory ¶
func RegisterParserFactory(factory parserFactory)
RegisterParserFactory lets users plug in factory functions that can generate parsers for entire categories of types (e.g., anything implementing TextUnmarshaler). Factories are checked in registration order before falling back to explicit parsers.
Types ¶
type FieldSetting ¶
type FieldSetting struct {
Path string // Dot-separated field path (e.g., "DB.Host")
FieldName string // Struct field name
EnvVar string // Environment variable name
Type string // Go type name
Default string // Default value from tag
Required bool // Whether field is required
Secret bool // Whether field is marked as secret
Tags map[string]string // All struct tags
}
FieldSetting represents metadata about a configuration field
func FilterSettings ¶
func FilterSettings(settings []FieldSetting, predicate func(FieldSetting) bool) []FieldSetting
FilterSettings returns settings matching the given predicate function
func RequiredFields ¶
func RequiredFields(config any) []FieldSetting
RequiredFields returns all required fields
func SecretFields ¶
func SecretFields(config any) []FieldSetting
SecretFields returns all fields marked as secrets
func Settings ¶
func Settings(config any) []FieldSetting
Settings returns metadata about all configuration fields in the struct. It recursively traverses nested structs and collects tag information.