### Minimal Configuration Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md A basic struct with a single environment variable tag. ```go type Config struct { Port int `env:"PORT"` } ``` -------------------------------- ### Install env Library Source: https://github.com/caarlos0/env/blob/main/README.md Use go get to install the latest version of the env library. ```bash go get github.com/caarlos0/env/v11 ``` -------------------------------- ### Env Tag Examples Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Provides examples of the 'env' tag with various options including 'required', 'file', and 'unset', as well as 'envDefault' for fields without environment variables. ```go type Config struct { // Basic usage - required Port int `env:"PORT,required"` // With default Host string `env:"HOST" envDefault:"localhost"` // File content ApiKey string `env:"API_KEY,file"` // Multiple options Secret string `env:"SECRET,required,file,unset"` // No env variable (just default) Timeout int `envDefault:"30"` // Ignored field InternalState string `env:"-"` } ``` -------------------------------- ### Required and Optional Fields Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Example showing how to mark fields as required or optional using tags. ```go type Config struct { ApiKey string `env:"API_KEY,required"` Port int `env:"PORT" envDefault:"8080"` CertPath string `env:"CERT_FILE,required,file"` DebugMode bool `env:"DEBUG"` } ``` -------------------------------- ### File Option Use Case Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Illustrates a practical use case for the 'file' option, where sensitive data like certificates is loaded from files specified by environment variables. ```go // Environment: // CERT_FILE=/etc/certs/server.pem // Code: type Config struct { Cert string `env:"CERT_FILE,file"` } // cfg.Cert will contain the full content of /etc/certs/server.pem ``` -------------------------------- ### NotEmpty Option Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Illustrates the 'notEmpty' tag option, requiring both the presence and a non-empty value for an environment variable. ```go type Config struct { Host string `env:"HOST,notEmpty"` } // Fails if HOST is not set // Fails if HOST="" // Works if HOST="localhost" ``` -------------------------------- ### File Option Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Demonstrates the 'file' tag option, which instructs the env package to read the content of a file specified by the environment variable's value. ```go type Config struct { Certificate string `env:"CERT_FILE,file"` } // If CERT_FILE="/path/to/cert.pem" // The field gets the content of /path/to/cert.pem ``` -------------------------------- ### Custom Tag Names Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Shows how to use custom tag names like 'json' and 'default' with the env package by configuring the ParseWithOptions function. ```go // Using custom tag names type Config struct { Port int `json:"PORT" default:"8080"` } // Parse with custom tag names env.ParseWithOptions(&cfg, env.Options{ TagName: "json", DefaultValueTagName: "default", }) ``` -------------------------------- ### GetFieldParams Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/api-reference/inspection.md Demonstrates how to use GetFieldParams to inspect a Config struct and print metadata about its environment variable mappings. This is useful for generating documentation or understanding env var requirements. ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { ApiKey string `env:"API_KEY,required"` Port int `env:"PORT" envDefault:"8080"` Host string `env:"HOST"` Secret string `env:"SECRET,unset"` Debug bool // No env tag, will be ignored } func main() { params, err := env.GetFieldParams(&Config{}) if err != nil { fmt.Println("Error:", err) return } for _, param := range params { fmt.Printf("Key: %s, Required: %v, HasDefault: %v, Default: %q\n", param.Key, param.Required, param.HasDefaultValue, param.DefaultValue) } // Output: // Key: API_KEY, Required: true, HasDefault: false, Default: "" // Key: PORT, Required: false, HasDefault: true, Default: "8080" // Key: HOST, Required: false, HasDefault: false, Default: "" // Key: SECRET, Required: false, HasDefault: false, Default: "" } ``` -------------------------------- ### Handling File Read Errors with LoadFileContentError Source: https://github.com/caarlos0/env/blob/main/_autodocs/errors.md Provides a comprehensive example of handling `env.LoadFileContentError` by checking for specific OS errors like `os.IsNotExist` and `os.IsPermission` when reading files. ```go package main import ( "errors" "fmt" "os" "github.com/caarlos0/env/v11" ) type Config struct { Secret string `env:"SECRET_FILE,file"` } func main() { var cfg Config err := env.Parse(&cfg) if err != nil { var aggErr env.AggregateError if errors.As(err, &aggErr) { for _, e := range aggErr.Errors { if loadErr, ok := e.(env.LoadFileContentError); ok { if os.IsNotExist(loadErr.Err) { fmt.Printf("Secret file not found: %s\n", loadErr.Filename) } else if os.IsPermission(loadErr.Err) { fmt.Printf("Permission denied reading: %s\n", loadErr.Filename) } else { fmt.Printf("Error reading %s: %v\n", loadErr.Filename, loadErr.Err) } } } } } } ``` -------------------------------- ### Custom String Type Parsing Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/types.md Shows how to create a custom parser for a string type that converts the input to uppercase. This is useful for enforcing specific string formats from environment variables. ```go package main import ( "fmt" "reflect" "strings" "github.com/caarlos0/env/v11" ) type UpperString string func parseUpperString(v string) (interface{}, error) { return UpperString(strings.ToUpper(v)), nil } type Config struct { Command UpperString `env:"COMMAND"` } func main() { cfg := Config{} err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "COMMAND": "start", }, FuncMap: map[reflect.Type]env.ParserFunc{ reflect.TypeOf(UpperString("")): parseUpperString, }, }) if err != nil { fmt.Println(err) return } fmt.Println(cfg.Command) // "START" } ``` -------------------------------- ### Define Nested Structs with Prefixes Source: https://github.com/caarlos0/env/blob/main/_autodocs/advanced-patterns.md Define deeply nested configuration structures using `envPrefix` for clear organization. This example shows how to structure database and cache configurations with nested credentials. ```go type Database struct { Host string `env:"HOST"` Port int `env:"PORT" envDefault:"5432"` Credentials struct { Username string `env:"USER"` Password string `env:"PASSWORD,required"` } `envPrefix:"CRED_"` } type Cache struct { Host string `env:"HOST" envDefault:"localhost"` Port int `env:"PORT" envDefault:"6379"` } type Config struct { Database Database `envPrefix:"DB_"` Cache Cache `envPrefix:"CACHE_"` } // Expected variables: // DB_HOST, DB_PORT, DB_CRED_USER, DB_CRED_PASSWORD // CACHE_HOST, CACHE_PORT ``` -------------------------------- ### Duration Parse Failure Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/errors.md Shows how to extract and display a ParseError when a duration field cannot be parsed from an environment variable. ```Go package main import ( "errors" "fmt" "time" "github.com/caarlos0/env/v11" ) type Config struct { Timeout time.Duration `env:"TIMEOUT"` } func main() { var cfg Config err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "TIMEOUT": "invalid-duration", }, }) if err != nil { var aggErr env.AggregateError errors.As(err, &aggErr) for _, e := range aggErr.Errors { if perr, ok := e.(env.ParseError); ok { fmt.Printf("Failed to parse %s: %v\n", perr.Name, perr.Err) } } } } ``` -------------------------------- ### Integer Parse Failure Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/errors.md Demonstrates handling a ParseError when an environment variable intended for an integer field is not a valid number. ```Go package main import ( "errors" "fmt" "github.com/caarlos0/env/v11" ) type Config struct { Port int `env:"PORT"` } func main() { var cfg Config err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "PORT": "not-a-number", }, }) if err != nil { if errors.Is(err, env.ParseError{}) { fmt.Println("Failed to parse numeric field") } } } ``` -------------------------------- ### Required Option Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Demonstrates the 'required' tag option, which enforces that an environment variable must be set, though its value can be empty. ```go type Config struct { ApiKey string `env:"API_KEY,required"` } // Fails if API_KEY is not set // Works if API_KEY is set to empty string "" ``` -------------------------------- ### Struct Tag Reference: env Source: https://github.com/caarlos0/env/blob/main/_autodocs/README.md Example of the 'env' struct tag used to specify environment variable names and options. ```go `env:"VARIABLE_NAME,option1,option2"` ``` -------------------------------- ### NotEmpty with EnvDefault Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Shows the interaction between 'notEmpty' and 'envDefault', where the default value is used if the variable is not set, but an error occurs if it's set but empty. ```go type Config struct { // If TIMEOUT not set, uses "30" (no error) // If TIMEOUT="", raises error Timeout string `env:"TIMEOUT,notEmpty" envDefault:"30"` } ``` -------------------------------- ### Post-Parse Validation Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/advanced-patterns.md Implement custom validation logic after environment variables have been parsed into a struct. This is useful for cross-field validation or business logic checks. ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { Host string `env:"HOST" envDefault:"localhost"` Port int `env:"PORT" envDefault:"8080"` MinPool int `env:"MIN_POOL" envDefault:"5"` MaxPool int `env:"MAX_POOL" envDefault:"20"` } func (c *Config) Validate() error { if c.Port < 1 || c.Port > 65535 { return fmt.Errorf("invalid port: %d", c.Port) } if c.MinPool > c.MaxPool { return fmt.Errorf("min_pool (%d) cannot exceed max_pool (%d)", c.MinPool, c.MaxPool) } return nil } func main() { var cfg Config if err := env.Parse(&cfg); err != nil { fmt.Println("Parse error:", err) return } if err := cfg.Validate(); err != nil { fmt.Println("Validation error:", err) return } fmt.Printf("Valid config: %+v\n", cfg) } ``` -------------------------------- ### Custom Duration Type Parsing Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/types.md Demonstrates how to implement a custom parser for a duration type using ParserFunc. This allows parsing environment variables into a custom struct like CustomDuration. ```go package main import ( "fmt" "reflect" "strconv" "github.com/caarlos0/env/v11" ) type CustomDuration struct { Seconds int } func parseCustomDuration(v string) (interface{}, error) { seconds, err := strconv.Atoi(v) if err != nil { return nil, fmt.Errorf("invalid duration: %w", err) } return CustomDuration{Seconds: seconds}, nil } type Config struct { Timeout CustomDuration `env:"TIMEOUT"` } func main() { cfg := Config{} err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "TIMEOUT": "30", }, FuncMap: map[reflect.Type]env.ParserFunc{ reflect.TypeOf(CustomDuration{}): parseCustomDuration, }, }) if err != nil { fmt.Println(err) return } fmt.Printf("Timeout: %d seconds\n", cfg.Timeout.Seconds) } ``` -------------------------------- ### Enum Type Parsing Example Source: https://github.com/caarlos0/env/blob/main/_autodocs/types.md Illustrates parsing an environment variable into a defined enum type (LogLevel). It handles valid enum values and returns an error for invalid ones. ```go package main import ( "fmt" "reflect" "github.com/caarlos0/env/v11" ) type LogLevel string const ( Debug LogLevel = "DEBUG" Info LogLevel = "INFO" Warn LogLevel = "WARN" Error LogLevel = "ERROR" ) func parseLogLevel(v string) (interface{}, error) { switch v { case "DEBUG", "INFO", "WARN", "ERROR": return LogLevel(v), nil default: return nil, fmt.Errorf("invalid log level: %s", v) } } type Config struct { Level LogLevel `env:"LOG_LEVEL" envDefault:"INFO"` } func main() { cfg := Config{} err := env.ParseWithOptions(&cfg, env.Options{ FuncMap: map[reflect.Type]env.ParserFunc{ reflect.TypeOf(LogLevel("")): parseLogLevel, }, }) if err != nil { fmt.Println(err) } } ``` -------------------------------- ### GetFieldParamsWithOptions Example with Custom Tag Names Source: https://github.com/caarlos0/env/blob/main/_autodocs/api-reference/inspection.md Demonstrates using GetFieldParamsWithOptions with custom tag names ('json' for env var and 'default' for default value). This allows flexibility when struct tags differ from the default 'env' and 'envDefault'. ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { DbHost string `json:"HOST" default:"localhost"` DbPort int `json:"PORT" default:"5432"` } func main() { params, err := env.GetFieldParamsWithOptions(&Config{}, env.Options{ TagName: "json", DefaultValueTagName: "default", }) if err != nil { fmt.Println("Error:", err) return } for _, param := range params { fmt.Printf("Field uses env var: %s (default: %q)\n", param.Key, param.DefaultValue) } // Output: // Field uses env var: HOST (default: "localhost") // Field uses env var: PORT (default: "5432") } ``` -------------------------------- ### Parse with Basic Options Source: https://github.com/caarlos0/env/blob/main/_autodocs/types.md Demonstrates parsing configuration with a specified prefix for environment variables. Other options will use their default values. ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { Port int `env:"PORT" envDefault:"8080"` } func main() { var cfg Config err := env.ParseWithOptions(&cfg, env.Options{ // Uses default for everything else Prefix: "APP_", }) if err != nil { fmt.Println(err) } } ``` -------------------------------- ### Fallback Chain for Configuration Source: https://github.com/caarlos0/env/blob/main/_autodocs/advanced-patterns.md Demonstrates a fallback chain to load configuration, trying a production database, then a development database, and finally an in-memory SQLite database. ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { Database string `env:"DATABASE_URL,required"` } func parseWithFallback() (*Config, error) { // Try production database first var cfg Config if err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "DATABASE_URL": "postgres://prod-db:5432/app", }, }); err == nil { return &cfg, nil } // Fall back to development database if err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "DATABASE_URL": "postgres://localhost:5432/app_dev", }, }); err == nil { return &cfg, nil } // Last resort: in-memory cfg.Database = "sqlite::memory:" return &cfg, nil } func main() { cfg, err := parseWithFallback() if err != nil { fmt.Println("Error:", err) return } fmt.Printf("Database: %s\n", cfg.Database) } ``` -------------------------------- ### File-based Configuration Loading Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Demonstrates using the 'file' tag to load values from files specified in environment variables. ```go type Config struct { DbPassword string `env:"DB_PASS_FILE,file,required"` ApiSecret string `env:"API_SECRET,file"` Certificate string `env:"CERT_PATH,file,unset"` } ``` -------------------------------- ### Struct Tag Reference: envSeparator Source: https://github.com/caarlos0/env/blob/main/_autodocs/README.md Example of the 'envSeparator' struct tag used to specify a custom separator for slice elements. ```go `envSeparator:";"` ``` -------------------------------- ### Struct Tag Reference: envDefault Source: https://github.com/caarlos0/env/blob/main/_autodocs/README.md Example of the 'envDefault' struct tag used to provide a default value for an environment variable. ```go `envDefault:"default-value"` ``` -------------------------------- ### Custom Tag Names for Options Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Demonstrates how to customize the tag names used for environment variable configuration. ```go type Config struct { Port int `config:"PORT" default:"8080"` } env.ParseWithOptions(&cfg, env.Options{ TagName: "config", DefaultValueTagName: "default", PrefixTagName: "prefix", }) ``` -------------------------------- ### File Structure Overview Source: https://github.com/caarlos0/env/blob/main/_autodocs/README.md Lists the main Go files and their purposes within the env project. This helps understand the project's organization and where to find specific functionalities. ```text env.go # Main parsing logic, types, and functions error.go # Error type definitions env_tomap.go # ToMap utility (Unix-like systems) env_tomap_windows.go # ToMap utility (Windows) ``` -------------------------------- ### Struct Tag Reference: envKeyValSeparator Source: https://github.com/caarlos0/env/blob/main/_autodocs/README.md Example of the 'envKeyValSeparator' struct tag used to specify a custom separator for map key-value pairs. ```go `envKeyValSeparator:"="` ``` -------------------------------- ### Env Tag Syntax Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Illustrates the syntax for the 'env' tag, specifying the environment variable name and optional parameters like 'required' or 'file'. ```go `env:"VARIABLE_NAME[,option1,option2,...]"` ``` -------------------------------- ### Struct Tag Reference: envPrefix Source: https://github.com/caarlos0/env/blob/main/_autodocs/README.md Example of the 'envPrefix' struct tag used to prefix environment variable names for nested structs. ```go `envPrefix:"PREFIX_"` ``` -------------------------------- ### Struct Tag Syntax Overview Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Demonstrates the basic structure and common options for env package struct tags, including required fields, defaults, prefixes, and separators. ```go type Config struct { // Tag name: env // Variable: PORT // Option: required (make it mandatory) Port int `env:"PORT,required"` // Tag name: envDefault // Default: 8080 (used if variable not set) Port2 int `env:"PORT2" envDefault:"8080"` // Prefix for nested struct Database Database `envPrefix:"DB_"` // Separator for slices (default: ,) Hosts []string `env:"HOSTS" envSeparator:";"` // Separator for maps (default: :) Headers map[string]string `env:"HEADERS" envKeyValSeparator:"="` } ``` -------------------------------- ### Configuration Layering: Defaults → File → Environment Source: https://github.com/caarlos0/env/blob/main/_autodocs/advanced-patterns.md Combines defaults from envDefault tags, configuration from a JSON file, and overrides from environment variables. Use this pattern to manage configuration with progressive specificity. ```go package main import ( "encoding/json" "fmt" "os" "github.com/caarlos0/env/v11" ) type Config struct { Database string `env:"DB_URL" envDefault:"localhost:5432"` ApiKey string `env:"API_KEY,required"` Port int `env:"PORT" envDefault:"8080"` } func loadConfig(filePath string) (*Config, error) { // Step 1: Start with defaults from envDefault tags cfg := &Config{} // Step 2: Load from file if it exists if filePath != "" { if data, err := os.ReadFile(filePath); err == nil { if err := json.Unmarshal(data, cfg); err != nil { return nil, fmt.Errorf("parse config file: %w", err) } } } // Step 3: Override with environment variables // Only non-zero values from cfg will be preserved if err := env.ParseWithOptions(cfg, env.Options{ SetDefaultsForZeroValuesOnly: true, }); err != nil { return nil, err } return cfg, nil } func main() { cfg, err := loadConfig("config.json") if err != nil { fmt.Println("Error:", err) } fmt.Printf("Config: %+v\n", cfg) } ``` -------------------------------- ### Interaction with Global Prefix Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Demonstrates how a global prefix defined in env.Options is prepended to field prefixes. ```go type Config struct { Database Database `envPrefix:"DB_"` } env.ParseWithOptions(&cfg, env.Options{ Prefix: "APP_", }) // Expected: APP_DB_HOST, APP_DB_PORT ``` -------------------------------- ### Handle Optional Configuration Sections Source: https://github.com/caarlos0/env/blob/main/_autodocs/advanced-patterns.md Define optional configuration sections using pointers to structs. The `env:",init"` tag ensures the struct is initialized if any of its fields are present in the environment. ```go type DatabaseConfig struct { Url string Host string Port int Username string } type Config struct { AppName string // Optional database config Database *DatabaseConfig `env:",init"` } func main() { var cfg Config opts := env.Options{ UseFieldNameByDefault: true, } if err := env.ParseWithOptions(&cfg, opts); err != nil { fmt.Println("Error:", err) return } if cfg.Database != nil { fmt.Printf("Database: %+v\n", cfg.Database) } } ``` -------------------------------- ### Configuration with Dependency Injection Source: https://github.com/caarlos0/env/blob/main/_autodocs/advanced-patterns.md Integrates configuration parsing with a dependency injection container. The container is responsible for parsing configuration and providing services. ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type DatabaseService struct { url string } type Config struct { DbUrl string `env:"DATABASE_URL,required"` } type Container struct { config *Config db *DatabaseService } func NewContainer() (*Container, error) { cfg := &Config{} if err := env.Parse(cfg); err != nil { return nil, fmt.Errorf("parse config: %w", err) } return &Container{ config: cfg, db: &DatabaseService{url: cfg.DbUrl}, }, nil } func (c *Container) Database() *DatabaseService { return c.db } func main() { container, err := NewContainer() if err != nil { fmt.Println("Error:", err) return } db := container.Database() fmt.Printf("Database URL: %s\n", db.url) } ``` -------------------------------- ### Generate Environment Variable Documentation Source: https://github.com/caarlos0/env/blob/main/_autodocs/api-reference/inspection.md This pattern shows how to programmatically generate documentation for environment variables based on a struct definition. It iterates through inspected field parameters to list variable names, requirements, and default values. ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { HttpPort int `env:"HTTP_PORT" envDefault:"8080"` DbUrl string `env:"DATABASE_URL,required"` SecretFile string `env:"SECRET_FILE,file"` Debug bool `env:"DEBUG"` } func printEnvVarDoc() error { params, err := env.GetFieldParams(&Config{}) if err != nil { return err } fmt.Println("## Supported Environment Variables\n") for _, param := range params { if param.OwnKey == "" { continue } requirement := "optional" if param.Required { requirement = "required" } fmt.Printf("### %s (%s)\n", param.Key, requirement) if param.HasDefaultValue { fmt.Printf("Default: `%s`\n", param.DefaultValue) } if param.LoadFile { fmt.Println("Note: This variable should contain a file path") } fmt.Println() } return nil } ``` -------------------------------- ### Load Different Configs Based on Environment Source: https://github.com/caarlos0/env/blob/main/_autodocs/advanced-patterns.md Conditionally parse different configuration structs based on an environment variable like `APP_ENV`. This allows for distinct configurations for development, staging, and production. ```go package main import ( "fmt" "os" "github.com/caarlos0/env/v11" ) type DevelopmentConfig struct { LogLevel string `env:"LOG_LEVEL" envDefault:"debug"` Port int `env:"PORT" envDefault:"3000"` } type ProductionConfig struct { LogLevel string `env:"LOG_LEVEL" envDefault:"warning"` Port int `env:"PORT" envDefault:"8080"` ApiKey string `env:"API_KEY,required"` } func LoadConfig() (interface{}, error) { appEnv := os.Getenv("APP_ENV") if appEnv == "production" { var cfg ProductionConfig if err := env.Parse(&cfg); err != nil { return nil, err } return cfg, nil } var cfg DevelopmentConfig if err := env.Parse(&cfg); err != nil { return nil, err } return cfg, nil } func main() { cfg, err := LoadConfig() if err != nil { fmt.Println("Error:", err) return } fmt.Printf("Config: %+v\n", cfg) } ``` -------------------------------- ### Get Field Parameters for Environment Variables Source: https://github.com/caarlos0/env/blob/main/_autodocs/api-reference/inspection.md Use `GetFieldParams` to retrieve a map of environment variable configurations from a struct. This is useful for understanding required fields, default values, and file loading options without parsing actual environment variables. ```Go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { AppName string `env:"APP_NAME" envDefault:"MyApp"` Version string `env:"APP_VERSION,required"` LogUrl string `env:"LOG_URL" envDefault:"http://localhost:3000"` } func buildVariableRequirements() (map[string]interface{}, error) { params, err := env.GetFieldParams(&Config{}) if err != nil { return nil, err } result := make(map[string]interface{}) for _, param := range params { if param.OwnKey == "" { continue } var defaultVal interface{} = nil if param.HasDefaultValue { defaultVal = param.DefaultValue } result[param.Key] = map[string]interface{}{ "required": param.Required, "default": defaultVal, "loadFile": param.LoadFile, } } return result, nil } ``` -------------------------------- ### Handling Missing Required Environment Variables Source: https://github.com/caarlos0/env/blob/main/_autodocs/errors.md Demonstrates how to check for and handle VarIsNotSetError when a required environment variable is missing. It also shows how default values prevent this error. ```go package main import ( "errors" "fmt" "github.com/caarlos0/env/v11" ) type Config struct { ApiKey string `env:"API_KEY,required"` Port int `env:"PORT" envDefault:"8080"` // This is fine with a default } func main() { var cfg Config err := env.Parse(&cfg) if err != nil && errors.Is(err, env.VarIsNotSetError{}) { fmt.Println("API_KEY is required but not set") } } ``` -------------------------------- ### Configuration with Context Timeouts Source: https://github.com/caarlos0/env/blob/main/_autodocs/advanced-patterns.md Loads configuration within a specified timeout using goroutines and channels. Returns an error if loading exceeds the timeout duration. ```go package main import ( "context" "fmt" "time" "github.com/caarlos0/env/v11" ) type Config struct { Timeout int `env:"TIMEOUT_SECONDS" envDefault:"30"` } func LoadConfigWithTimeout(timeout time.Duration) (*Config, error) { done := make(chan *Config, 1) errors := make(chan error, 1) go func() { cfg := &Config{} if err := env.Parse(cfg); err != nil { errors <- err } else { done <- cfg } }() select { case cfg := <-done: return cfg, nil case err := <-errors: return nil, err case <-time.After(timeout): return nil, fmt.Errorf("config load timeout") } } func main() { cfg, err := LoadConfigWithTimeout(5 * time.Second) if err != nil { fmt.Println("Error:", err) return } fmt.Printf("Config: %+v\n", cfg) } ``` -------------------------------- ### Create Custom Environment Snapshot Source: https://github.com/caarlos0/env/blob/main/_autodocs/api-reference/helpers.md Captures the current environment and allows for modification to create a custom snapshot for testing or specific configurations. Useful for setting up predictable environments for tests. ```go package main import ( "fmt" "os" "github.com/caarlos0/env/v11" ) type Config struct { DbHost string `env:"DB_HOST" DbPort int `env:"DB_PORT" } func loadWithSnapshot() error { // Capture current environment snapshot := env.ToMap(os.Environ()) // Modify for testing snapshot["DB_HOST"] = "testdb.example.com" snapshot["DB_PORT"] = "5432" var cfg Config return env.ParseWithOptions(&cfg, env.Options{ Environment: snapshot, }) } func main() { if err := loadWithSnapshot(); err != nil { fmt.Println("Error:", err) return } fmt.Println("Config loaded successfully") } ``` -------------------------------- ### Monitor Value Setting with OnSet Hook Source: https://github.com/caarlos0/env/blob/main/_autodocs/README.md Implement an OnSet hook to execute a function whenever an environment variable is successfully set. ```go var cfg Config if err := env.ParseWithOptions(&cfg, env.Options{ OnSet: func(tag string, value interface{}, isDefault bool) { fmt.Printf("Set %s=%v (from %v)\n", tag, value, map[bool]string{true: "default", false: "environment"}[isDefault]) }, }); err != nil { // Handle error } ``` -------------------------------- ### File Option with Other Options Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Shows how the 'file' option can be combined with other tag options like 'required' and 'unset'. ```go `env:"SECRET,file,required"` // File must exist `env:"SECRET,file,unset"` // Unset after reading ``` -------------------------------- ### Complex Nesting with Multiple Levels Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Demonstrates deep nesting of structs with `envPrefix` for hierarchical configuration. ```go type Credentials struct { Username string `env:"USERNAME,required"` Password string `env:"PASSWORD,required,file"` } type Database struct { Host string `env:"HOST" envDefault:"localhost"` Port int `env:"PORT" envDefault:"5432"` Name string `env:"NAME,required"` Credentials Credentials `envPrefix:""` } type Redis struct { Host string `env:"HOST" envDefault:"localhost"` Port int `env:"PORT" envDefault:"6379"` } type Config struct { Primary Database `envPrefix:"PRIMARY_DB_"` Replica Database `envPrefix:"REPLICA_DB_"` Cache Redis `envPrefix:"CACHE_"` ApiKey string `env:"API_KEY,required"` DebugMode bool `env:"DEBUG" envDefault:"false"` LogPath string `env:"LOG_FILE,file"` } ``` -------------------------------- ### Parse Environment Variables with Custom Options and Error Handling Source: https://github.com/caarlos0/env/blob/main/_autodocs/types.md Demonstrates parsing environment variables into a struct with required fields and custom options, including handling specific error types like missing variables and aggregate errors. ```go package main import ( "fmt" "errors" "github.com/caarlos0/env/v11" ) type Config struct { Required1 string `env:"REQ1,required"` Required2 string `env:"REQ2,required" Invalid int `env:"INVALID"` } func main() { var cfg Config err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "INVALID": "not-a-number", }, }) if err != nil { // Check for specific error types if errors.Is(err, env.VarIsNotSetError{}) { fmt.Println("Some required variables are missing") } // Iterate through all errors var aggErr env.AggregateError if errors.As(err, &aggErr) { for _, e := range aggErr.Errors { fmt.Printf("Error: %v\n", e) } } } } ``` -------------------------------- ### Pointer Initialization Source: https://github.com/caarlos0/env/blob/main/_autodocs/api-reference/parsing.md Configure pointer fields within structs for environment variable parsing. The `env:",init"` tag ensures initialization even if no environment variables match. ```go type Inner struct { Value string `env:"VALUE" envDefault:"initialized"` } type Config struct { // Remains nil if no env vars match NoInit *Inner // Always initialized, even if no env vars WithInit *Inner `env:",init"` } ``` -------------------------------- ### Log Set Values with OnSet Hook Source: https://github.com/caarlos0/env/blob/main/_autodocs/types.md Use the OnSet hook to log environment variable keys, their parsed values, and whether they originated from the environment or a default. ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { ApiKey string `env:"API_KEY,required"` Port int `env:"PORT" envDefault:"8080"` } func main() { var cfg Config err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "API_KEY": "secret123", }, OnSet: func(tag string, value interface{}, isDefault bool) { source := "environment" if isDefault { source = "default" } fmt.Printf("Set %s=%v (from %s)\n", tag, value, source) }, }) if err != nil { fmt.Println(err) return } // Output: // Set API_KEY=secret123 (from environment) // Set PORT=8080 (from default) } ``` -------------------------------- ### Parse with Custom Environment Variables Source: https://github.com/caarlos0/env/blob/main/_autodocs/types.md Parses configuration using a custom map of environment variables instead of the system's environment. Useful for testing or specific environments. ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { Host string `env:"DB_HOST"` Port int `env:"DB_PORT"` } func main() { var cfg Config err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "DB_HOST": "localhost", "DB_PORT": "5432", }, }) if err != nil { fmt.Println(err) } // cfg = Config{Host: "localhost", Port: 5432} } ``` -------------------------------- ### Options Struct Definition Source: https://github.com/caarlos0/env/blob/main/_autodocs/types.md Defines the configuration options for parsing environment variables. It includes fields for custom environments, tag names, default values, hooks, prefixes, and custom parsers. ```go type Options struct { // Environment maps environment variable names to their values. // If not set, os.Environ() is used by default. Environment map[string]string // TagName specifies the struct tag name for environment variables. // Default is "env" TagName string // PrefixTagName specifies the struct tag name for prefix configuration. // Default is "envPrefix" PrefixTagName string // DefaultValueTagName specifies the struct tag name for default values. // Default is "envDefault" DefaultValueTagName string // RequiredIfNoDef automatically makes all fields required if they don't have envDefault. RequiredIfNoDef bool // OnSet is called whenever a value is set during parsing. // Signature: func(tag string, value interface{}, isDefault bool) OnSet OnSetFn // Prefix is prepended to all environment variable keys. // Useful for namespacing when multiple configs share similar variable names. Prefix string // UseFieldNameByDefault uses the field name to derive the environment variable name // if no env tag is present. // Field names are converted to UPPER_SNAKE_CASE (e.g., FooBar -> FOO_BAR) UseFieldNameByDefault bool // SetDefaultsForZeroValuesOnly only applies envDefault values to zero-valued fields. // Useful when merging config from multiple sources (file + environment). SetDefaultsForZeroValuesOnly bool // FuncMap provides custom parsers for specific types. // Key is the reflect.Type, value is a ParserFunc FuncMap map[reflect.Type]ParserFunc } ``` -------------------------------- ### Configuration with Default Values Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Struct demonstrating the use of envDefault tags for providing fallback values. ```go type Config struct { Port int `env:"PORT" envDefault:"8080"` Host string `env:"HOST" envDefault:"localhost"` Timeout int `env:"TIMEOUT" envDefault:"30"` } ``` -------------------------------- ### Build Metadata Map with OnSet Hook Source: https://github.com/caarlos0/env/blob/main/_autodocs/types.md Utilize the OnSet hook to construct a metadata map containing parsed values and their origin (environment or default). ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { Host string `env:"HOST" envDefault:"localhost"` Port int `env:"PORT" envDefault:"5432"` Username string `env:"USERNAME,required"` } func main() { metadata := make(map[string]map[string]interface{}) var cfg Config err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "HOST": "db.example.com", "USERNAME": "admin", }, OnSet: func(tag string, value interface{}, isDefault bool) { metadata[tag] = map[string]interface{}{ "value": value, "default": isDefault, } }, }) if err != nil { fmt.Println(err) return } fmt.Printf("Configuration loaded with metadata:\n") for key, info := range metadata { fmt.Printf(" %s = %v (default: %v)\n", key, info["value"], info["default"]) } } ``` -------------------------------- ### Correctly Parsing Struct Pointers Source: https://github.com/caarlos0/env/blob/main/_autodocs/errors.md Demonstrates the correct way to parse environment variables into a struct by passing a pointer to the struct. This avoids the 'expected a pointer to a Struct' error. ```go package main import ( "fmt" "github.com/caarlos0/env/v11" ) type Config struct { Host string `env:"HOST"` } func main() { cfg := Config{} // WRONG: passing struct value, not pointer err := env.Parse(cfg) if err != nil { fmt.Println(err) // expected a pointer to a Struct } // CORRECT: passing pointer to struct err = env.Parse(&cfg) if err != nil { fmt.Println(err) } } ``` -------------------------------- ### Handling LoadFileContentError for Missing Files Source: https://github.com/caarlos0/env/blob/main/_autodocs/errors.md Shows how to detect and handle `env.LoadFileContentError` when the `file` tag option is used and the specified file does not exist. ```go package main import ( "errors" "fmt" "github.com/caarlos0/env/v11" ) type Config struct { // Read certificate content from a file CertFile string `env:"CERT_PATH,file"` } func main() { var cfg Config err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "CERT_PATH": "/path/to/nonexistent/file.pem", }, }) if err != nil { var aggErr env.AggregateError errors.As(err, &aggErr) for _, e := range aggErr.Errors { if loadErr, ok := e.(env.LoadFileContentError); ok { fmt.Printf("Cannot read file %s: %v\n", loadErr.Filename, loadErr.Err) } } } } ``` -------------------------------- ### File Organization Overview Source: https://github.com/caarlos0/env/blob/main/_autodocs/DOCUMENTATION_INDEX.md This snippet shows the directory structure of the caarlos0/env documentation. ```tree output/ ├── README.md # Main index and quick reference ├── types.md # Type definitions and interfaces ├── errors.md # Error types and handling ├── struct-tags-reference.md # Comprehensive tag guide ├── advanced-patterns.md # Advanced usage patterns ├── api-reference/ │ ├── parsing.md # Core parsing functions │ ├── inspection.md # Field introspection functions │ └── helpers.md # Helper utilities └── DOCUMENTATION_INDEX.md # This file ``` -------------------------------- ### Auto-generate Markdown Documentation Source: https://github.com/caarlos0/env/blob/main/_autodocs/advanced-patterns.md Programmatically generate Markdown documentation for environment variables by inspecting struct tags. This helps keep documentation in sync with code. ```go package main import ( "fmt" "os" "github.com/caarlos0/env/v11" ) type Config struct { Port int `env:"PORT" envDefault:"8080"` Host string `env:"HOST" envDefault:"localhost"` ApiKey string `env:"API_KEY,required"` DebugMode bool `env:"DEBUG"` CertFile string `env:"CERT_FILE,file"` ExpandPath string `env:"PATH,expand" envDefault:"${HOME}/config"` } func generateDocumentation(cfg interface{}) error { params, err := env.GetFieldParams(cfg) if err != nil { return err } fmt.Println("# Environment Variables\n") for _, param := range params { if param.OwnKey == "" { continue } fmt.Printf("## %s\n\n", param.Key) if param.Required { fmt.Println("**Required**\n") } if param.HasDefaultValue { fmt.Printf("**Default:** `%s`\n\n", param.DefaultValue) } // Document special behaviors if param.LoadFile { fmt.Println("This variable should contain a file path to be read.\n") } if param.Expand { fmt.Println("Environment variable references will be expanded (e.g., `${VAR}`).\n") } if param.NotEmpty { fmt.Println("This variable cannot be empty.\n") } fmt.Println() } return nil } func main() { if err := generateDocumentation(&Config{}); err != nil { fmt.Println("Error:", err) os.Exit(1) } } ``` -------------------------------- ### Nested Structs with Prefixes Source: https://github.com/caarlos0/env/blob/main/_autodocs/api-reference/parsing.md Define nested structs with environment variable prefixes to organize configuration. Expects environment variables like DB_HOST, DB_PORT, CACHE_HOST, CACHE_PORT. ```go type Database struct { Host string `env:"HOST"` Port int `env:"PORT,required"` } type Cache struct { Host string `env:"HOST"` Port int `env:"PORT" envDefault:"6379"` } type Config struct { Db Database `envPrefix:"DB_"` Cache Cache `envPrefix:"CACHE_"` } // Expects: DB_HOST, DB_PORT, CACHE_HOST, CACHE_PORT ``` -------------------------------- ### Initialize Nil Pointers Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md The `init` tag ensures that nil pointers are initialized to zero-valued structs, preventing nil dereference panics. This is particularly useful for nested configuration structs. ```Go type Inner struct { Value string `env:"VALUE" envDefault:"default"` } type Config struct { NoInit *Inner `env:",file"` // Remains nil if no env vars match WithInit *Inner `env:",init"` // Always initialized } ``` ```Go type DatabaseConfig struct { Host string `env:"HOST" envDefault:"localhost"` Port int `env:"PORT" envDefault:"5432"` } type Config struct { // Always initialized, even if no DB_* variables Database *DatabaseConfig `env:",init" envPrefix:"DB_"` } ``` -------------------------------- ### Handling Empty Required Value Source: https://github.com/caarlos0/env/blob/main/_autodocs/errors.md Demonstrates how to catch and handle `env.EmptyVarError` when a required and non-empty environment variable is not provided or is empty. ```go package main import ( "errors" "fmt" "github.com/caarlos0/env/v11" ) type Config struct { // Value must be set AND non-empty Host string `env:"HOST,notEmpty"` } func main() { var cfg Config err := env.ParseWithOptions(&cfg, env.Options{ Environment: map[string]string{ "HOST": "", // Empty! }, }) if err != nil && errors.Is(err, env.EmptyVarError{}) { fmt.Println("HOST must not be empty") } } ``` -------------------------------- ### Parse Custom Config with Options Source: https://github.com/caarlos0/env/blob/main/_autodocs/api-reference/parsing.md Parses environment variables into a Config struct using custom options, including a specific environment map and requiring variables if no default is set. ```go package main import ( "fmt" "reflect" "github.com/caarlos0/env/v11" ) type CustomInt struct { value int } type Config struct { Timeout int `env:"TIMEOUT"` Retries int `env:"RETRIES" envDefault:"3"` } func main() { customEnv := map[string]string{ "TIMEOUT": "30", } cfg, err := env.ParseAsWithOptions[Config](env.Options{ Environment: customEnv, RequiredIfNoDef: true, }) if err != nil { fmt.Println("Error:", err) return } fmt.Printf("Timeout: %d, Retries: %d\n", cfg.Timeout, cfg.Retries) // Output: Timeout: 30, Retries: 3 } ``` -------------------------------- ### Struct with Nested Prefixes Source: https://github.com/caarlos0/env/blob/main/_autodocs/struct-tags-reference.md Demonstrates how envPrefix accumulates through nested structs to form environment variable names. ```go type Database struct { Host string `env:"HOST"` Port int `env:"PORT"` } type Cache struct { Host string `env:"HOST"` Port int `env:"PORT"` } type Config struct { Database Database `envPrefix:"DB_"` Cache Cache `envPrefix:"CACHE_"` } ```