xconfig

package module
v0.2.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 15, 2025 License: MIT Imports: 15 Imported by: 0

README

xConfig

Go Reference Go Report Card

A lightweight, zero-dependency, and highly extensible configuration management library for Go applications.

Features

  • Zero Dependencies - No external dependencies in the core library
  • Plugin-Based Architecture - Mix and match only the configuration sources you need
  • Type-Safe - Strongly typed configuration with struct tags
  • Multiple Sources - Support for defaults, environment variables, command-line flags, and config files
  • Nested Structures - Full support for nested configuration structs
  • Rich Type Support - All basic Go types, time.Duration, and custom types via encoding.TextUnmarshaler
  • Validation - Built-in validation support through plugins
  • Documentation Generation - Auto-generate markdown documentation for your configuration

Installation

go get github.com/sxwebdev/xconfig

Quick Start

package main

import (
    "fmt"
    "log"

    "github.com/sxwebdev/xconfig"
)

type Config struct {
    Host     string `default:"localhost" env:"HOST" flag:"host" usage:"Server host address"`
    Port     int    `default:"8080" env:"PORT" flag:"port" usage:"Server port"`
    Debug    bool   `default:"false" env:"DEBUG" flag:"debug" usage:"Enable debug mode"`
    Database struct {
        Host     string `default:"localhost" env:"DB_HOST" usage:"Database host"`
        Port     int    `default:"5432" env:"DB_PORT" usage:"Database port"`
        Name     string `default:"myapp" env:"DB_NAME" usage:"Database name"`
        Password string `secret:"DB_PASSWORD" usage:"Database password"`
    }
}

func main() {
    cfg := &Config{}

    // Load configuration from defaults, env vars, and flags
    _, err := xconfig.Load(cfg)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Server: %s:%d\n", cfg.Host, cfg.Port)
    fmt.Printf("Database: %s:%d/%s\n", cfg.Database.Host, cfg.Database.Port, cfg.Database.Name)
}

Usage

Basic Configuration Loading

The Load function provides the most common configuration pattern, automatically enabling:

  1. Default values from struct tags
  2. Custom defaults via SetDefaults() method
  3. Configuration files (if provided)
  4. Environment variables
  5. Command-line flags
type AppConfig struct {
    APIKey    string `default:"dev-key" env:"API_KEY" flag:"api-key"`
    Timeout   int    `default:"30" env:"TIMEOUT" flag:"timeout"`
    EnableLog bool   `default:"true" env:"ENABLE_LOG" flag:"enable-log"`
}

cfg := &AppConfig{}
_, err := xconfig.Load(cfg)
Loading from Configuration Files

xConfig supports multiple configuration file formats through decoders:

import (
    "encoding/json"

    "github.com/sxwebdev/xconfig"
    "github.com/sxwebdev/xconfig/plugins/loader"
    "github.com/sxwebdev/xconfig/decoders/xconfigyaml"
    "github.com/sxwebdev/xconfig/decoders/xconfigdotenv"
)

type Config struct {
    Server struct {
        Host string `json:"host"`
        Port int    `json:"port"`
    } `json:"server"`
}

cfg := &Config{}

// Create loader with JSON decoder
l, err := loader.NewLoader(map[string]loader.Unmarshal{
    "json": json.Unmarshal,
    "yaml": xconfigyaml.New().Unmarshal,
    "env":  xconfigdotenv.New().Unmarshal,
})
if err != nil {
    log.Fatal(err)
}

// Add configuration file (optional=false means file must exist)
err = l.AddFile("config.json", false)
if err != nil {
    log.Fatal(err)
}

_, err = xconfig.Load(cfg, xconfig.WithLoader(l))
Environment Variables with Prefix
type Config struct {
    APIKey string `env:"API_KEY"`
    Secret string `env:"SECRET"`
}

cfg := &Config{}

// All env vars will be prefixed with "MYAPP_"
// So it will look for: MYAPP_API_KEY and MYAPP_SECRET
_, err := xconfig.Load(cfg, xconfig.WithEnvPrefix("MYAPP"))
Custom Defaults with SetDefaults

Implement the SetDefaults() method to programmatically set default values:

type Config struct {
    Host string
    Port int
    URLs []string
}

func (c *Config) SetDefaults() {
    c.Host = "localhost"
    c.Port = 8080
    c.URLs = []string{"https://api.example.com", "https://backup.example.com"}
}

cfg := &Config{}
_, err := xconfig.Load(cfg)
// cfg.Host will be "localhost" unless overridden by env or flags
Secret Management

Use the secret tag for sensitive data that should be loaded from a secret provider:

import (
    "github.com/sxwebdev/xconfig"
    "github.com/sxwebdev/xconfig/plugins/secret"
)

type Config struct {
    DBPassword string `secret:"DATABASE_PASSWORD"`
    APIToken   string `secret:"API_TOKEN"`
}

// Custom secret provider (e.g., AWS Secrets Manager, HashiCorp Vault, etc.)
secretProvider := func(name string) (string, error) {
    // Implement your secret fetching logic here
    switch name {
    case "DATABASE_PASSWORD":
        return fetchFromVault(name)
    case "API_TOKEN":
        return fetchFromAWS(name)
    default:
        return "", fmt.Errorf("secret not found: %s", name)
    }
}

cfg := &Config{}
_, err := xconfig.Load(cfg, xconfig.WithPlugins(secret.New(secretProvider)))
Validation

Add validation to ensure your configuration meets requirements:

import (
    "fmt"
    "github.com/sxwebdev/xconfig"
    "github.com/sxwebdev/xconfig/plugins/validate"
)

type Config struct {
    Port int    `default:"8080"`
    Host string `default:"localhost"`
}

// Implement Validate method
func (c *Config) Validate() error {
    if c.Port < 1 || c.Port > 65535 {
        return fmt.Errorf("port must be between 1 and 65535")
    }
    if c.Host == "" {
        return fmt.Errorf("host cannot be empty")
    }
    return nil
}

cfg := &Config{}

// Validation happens automatically after loading
_, err := xconfig.Load(cfg)
if err != nil {
    log.Fatal(err) // Will fail if validation fails
}

You can also use external validators:

import (
    "github.com/go-playground/validator/v10"
    "github.com/sxwebdev/xconfig/plugins/validate"
)

type Config struct {
    Email string `validate:"required,email"`
    Age   int    `validate:"gte=0,lte=130"`
}

cfg := &Config{}

v := validator.New()
_, err := xconfig.Load(cfg, xconfig.WithPlugins(
    validate.New(func(a any) error {
        return v.Struct(a)
    }),
))
Selective Plugin Loading

Control which plugins are enabled:

cfg := &Config{}

// Skip certain plugins
_, err := xconfig.Load(cfg,
    xconfig.WithSkipDefaults(),         // Don't load from 'default' tags
    xconfig.WithSkipEnv(),              // Don't load from environment
    xconfig.WithSkipFlags(),            // Don't load from command-line flags
    xconfig.WithSkipCustomDefaults(),   // Don't call SetDefaults()
    xconfig.WithDisallowUnknownFields(), // Fail if config files contain unknown fields
)

Unknown Fields Validation: Enable WithDisallowUnknownFields() to detect typos and configuration errors in JSON/YAML files. When enabled, loading will fail if any fields in the config files don't match your struct definition. Use xconfig.GetUnknownFields() to retrieve unknown fields without failing.

Documentation Generation

Generate markdown documentation for your configuration:

type Config struct {
    Host   string `default:"localhost" usage:"Server host address"`
    Port   int    `default:"8080" usage:"Server port number"`
    APIKey string `secret:"API_KEY" usage:"API authentication key"`
}

cfg := &Config{}

markdown, err := xconfig.GenerateMarkdown(cfg)
if err != nil {
    log.Fatal(err)
}

// Save to file
os.WriteFile("CONFIG.md", []byte(markdown), 0644)
Usage Information

Get runtime configuration information:

cfg := &Config{}
c, err := xconfig.Load(cfg)
if err != nil {
    log.Fatal(err)
}

usage, err := c.Usage()
if err != nil {
    log.Fatal(err)
}

fmt.Println(usage)

Available Struct Tags

Tag Description Example
default Default value for the field default:"8080"
env Environment variable name env:"PORT"
flag Command-line flag name flag:"port"
secret Secret identifier for secret provider secret:"DB_PASSWORD"
usage Description for documentation/help usage:"Server port"
xconfig Override field name in flat structure xconfig:"custom_name"

Available Plugins

Plugin Description
defaults Load values from default struct tags
customdefaults Call SetDefaults() method if implemented
env Load values from environment variables
flag Load values from command-line flags
loader Load values from configuration files (JSON, YAML, etc.)
secret Load sensitive values from secret providers
validate Validate configuration after loading

Custom Plugins

Create your own plugins by implementing the Plugin interface with either Walker or Visitor:

import (
    "github.com/sxwebdev/xconfig/flat"
    "github.com/sxwebdev/xconfig/plugins"
)

type myPlugin struct {
    fields flat.Fields
}

// Visitor interface - called once with all fields
func (p *myPlugin) Visit(fields flat.Fields) error {
    p.fields = fields
    // Setup phase: register metadata, validate structure, etc.
    return nil
}

// Parse is called to actually load configuration
func (p *myPlugin) Parse() error {
    for _, field := range p.fields {
        // Load configuration for each field
    }
    return nil
}

// Use your custom plugin
cfg := &Config{}
_, err := xconfig.Custom(cfg, &myPlugin{})

Supported Types

  • All basic Go types: string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64
  • time.Duration
  • Slices of supported types: []string, []int, etc.
  • Any type implementing encoding.TextUnmarshaler

Examples

See the examples directory for more complete examples.

License

MIT License

Documentation

Overview

Package xconfig provides a lightweight, zero-dependency, and highly extensible configuration management library for Go applications.

Overview

xconfig enables you to build type-safe configuration for your applications using a plugin-based architecture. Mix and match only the configuration sources you need: defaults, environment variables, command-line flags, configuration files, secret providers, and more.

Quick Start

Define your configuration as a struct with tags:

type Config struct {
    Host     string `default:"localhost" env:"HOST" flag:"host" usage:"Server host"`
    Port     int    `default:"8080" env:"PORT" flag:"port" usage:"Server port"`
    Debug    bool   `default:"false" env:"DEBUG" flag:"debug" usage:"Debug mode"`
    Database struct {
        Host     string `default:"localhost" env:"DB_HOST" usage:"Database host"`
        Port     int    `default:"5432" env:"DB_PORT" usage:"Database port"`
        Password string `secret:"DB_PASSWORD" usage:"Database password"`
    }
}

Load configuration from multiple sources:

cfg := &Config{}
_, err := xconfig.Load(cfg)
if err != nil {
    log.Fatal(err)
}

The Load function automatically processes configuration in this order:

  1. Default values from struct tags
  2. Custom defaults via SetDefaults() method
  3. Configuration files (if provided)
  4. Environment variables
  5. Command-line flags

Configuration Sources

## Default Values

Use the "default" tag to specify default values:

type Config struct {
    Port    int    `default:"8080"`
    Timeout int    `default:"30"`
    Enabled bool   `default:"true"`
}

## Environment Variables

Use the "env" tag to bind fields to environment variables:

type Config struct {
    APIKey string `env:"API_KEY"`
    Secret string `env:"SECRET"`
}

Add a prefix to all environment variables:

_, err := xconfig.Load(cfg, xconfig.WithEnvPrefix("MYAPP"))
// Will look for: MYAPP_API_KEY, MYAPP_SECRET

## Command-Line Flags

Use the "flag" tag to bind fields to command-line flags:

type Config struct {
    Host string `flag:"host" usage:"Server hostname"`
    Port int    `flag:"port" usage:"Server port"`
}

## Configuration Files

Load configuration from JSON, YAML, TOML, or any other format:

import (
    "encoding/json"
    "github.com/sxwebdev/xconfig/plugins/loader"
)

l, err := loader.NewLoader(map[string]loader.Unmarshal{
    ".json": json.Unmarshal,
    ".yaml": yaml.Unmarshal,
})
if err != nil {
    log.Fatal(err)
}

err = l.AddFile("config.json", false)
if err != nil {
    log.Fatal(err)
}

_, err = xconfig.Load(cfg, xconfig.WithLoader(l))

## Custom Defaults

Implement SetDefaults() for programmatic default values:

type Config struct {
    URLs []string
    Port int
}

func (c *Config) SetDefaults() {
    c.URLs = []string{"https://api.example.com"}
    c.Port = 8080
}

Secret Management

Use the secret plugin to load sensitive data from secret providers like AWS Secrets Manager, HashiCorp Vault, or Kubernetes secrets:

import "github.com/sxwebdev/xconfig/plugins/secret"

type Config struct {
    DBPassword string `secret:"DATABASE_PASSWORD"`
    APIToken   string `secret:"API_TOKEN"`
}

secretProvider := func(name string) (string, error) {
    // Fetch from your secret backend
    return fetchFromVault(name)
}

_, err := xconfig.Load(cfg, xconfig.WithPlugins(secret.New(secretProvider)))

Validation

Add validation by implementing the Validate() method:

type Config struct {
    Port int `default:"8080"`
}

func (c *Config) Validate() error {
    if c.Port < 1 || c.Port > 65535 {
        return fmt.Errorf("invalid port: %d", c.Port)
    }
    return nil
}

Or use external validators with the validate plugin:

import (
    "github.com/go-playground/validator/v10"
    "github.com/sxwebdev/xconfig/plugins/validate"
)

type Config struct {
    Email string `validate:"required,email"`
    Age   int    `validate:"gte=0,lte=130"`
}

v := validator.New()
_, err := xconfig.Load(cfg, xconfig.WithPlugins(
    validate.New(func(a any) error {
        return v.Struct(a)
    }),
))

Available Tags

The following struct tags are supported:

  • default: Default value for the field
  • env: Environment variable name
  • flag: Command-line flag name
  • secret: Secret identifier for secret provider
  • usage: Description for documentation and help text
  • xconfig: Override field name in flat structure

Supported Types

xconfig supports all basic Go types, time.Duration, slices of basic types, and any type implementing encoding.TextUnmarshaler:

  • string, bool
  • int, int8, int16, int32, int64
  • uint, uint8, uint16, uint32, uint64
  • float32, float64
  • time.Duration
  • []string, []int, []float64, etc.
  • Custom types via encoding.TextUnmarshaler

Custom Plugins

Create custom plugins by implementing the Plugin interface with either Walker or Visitor:

import (
    "github.com/sxwebdev/xconfig/flat"
    "github.com/sxwebdev/xconfig/plugins"
)

type myPlugin struct {
    fields flat.Fields
}

func (p *myPlugin) Visit(fields flat.Fields) error {
    p.fields = fields
    return nil
}

func (p *myPlugin) Parse() error {
    // Load configuration for each field
    return nil
}

// Use your plugin
_, err := xconfig.Custom(cfg, &myPlugin{})

Documentation Generation

Generate markdown documentation for your configuration:

markdown, err := xconfig.GenerateMarkdown(cfg)
if err != nil {
    log.Fatal(err)
}
os.WriteFile("CONFIG.md", []byte(markdown), 0644)

Options

Control which plugins are enabled:

_, err := xconfig.Load(cfg,
    xconfig.WithSkipDefaults(),      // Skip 'default' tags
    xconfig.WithSkipEnv(),            // Skip environment variables
    xconfig.WithSkipFlags(),          // Skip command-line flags
    xconfig.WithEnvPrefix("MYAPP"),   // Add prefix to env vars
    xconfig.WithPlugins(myPlugin),    // Add custom plugins
)

For more information and examples, see: https://github.com/sxwebdev/xconfig

Package xconfig provides advanced command line flags supporting defaults, env vars, and config structs.

Index

Constants

This section is empty.

Variables

View Source
var ErrUsage = plugins.ErrUsage

Functions

func GenerateMarkdown

func GenerateMarkdown(cfg any, opts ...Option) (string, error)

func GetUnknownFields

func GetUnknownFields(c Config) map[string][]string

GetUnknownFields returns all unknown fields found in configuration files. Returns a map where keys are file paths and values are slices of unknown field paths. This function is useful for debugging configuration issues or logging warnings about extra fields that are not used.

Types

type Config

type Config interface {
	// Parse will call the parse method of all the added pluginss in the order
	// that the pluginss were registered, it will return early as soon as any
	// plugins fails.
	// You must call this before using the config value.
	Parse() error

	// Usage provides a simple usage message based on the meta data registered
	// by the pluginss.
	Usage() (string, error)

	// Options returns the options for the config.
	Options() *options

	// Fields returns the flat fields that have been processed by plugins.
	Fields() flat.Fields
	// contains filtered or unexported methods
}

Config is the config manager.

func Custom

func Custom(conf any, ps ...plugins.Plugin) (Config, error)

Custom returns a new Config. The conf must be a pointer to a struct.

func Load

func Load(conf any, opts ...Option) (Config, error)

Load creates a xconfig manager with defaults, environment variables, and flags (in that order) and optionally file loaders based on the provided Files map and parses them right away.

type Option

type Option func(*options)

func WithDisallowUnknownFields

func WithDisallowUnknownFields() Option

func WithEnvPrefix

func WithEnvPrefix(prefix string) Option

func WithLoader

func WithLoader(loader *loader.Loader) Option

func WithPlugins

func WithPlugins(plugins ...plugins.Plugin) Option

func WithSkipCustomDefaults

func WithSkipCustomDefaults() Option

func WithSkipDefaults

func WithSkipDefaults() Option

func WithSkipEnv

func WithSkipEnv() Option

func WithSkipFiles

func WithSkipFiles() Option

func WithSkipFlags

func WithSkipFlags() Option

Directories

Path Synopsis
decoders
xconfigdotenv module
xconfigyaml module
Package flat provides a flat view of an arbitrary nested structs.
Package flat provides a flat view of an arbitrary nested structs.
internal
f
Package f provides simple test fixtures for xconfig.
Package f provides simple test fixtures for xconfig.
utils
original package located here https://github.com/mcuadros/go-lookup
original package located here https://github.com/mcuadros/go-lookup
Package plugins describes the xconfig provider interface.
Package plugins describes the xconfig provider interface.
customdefaults
Package defaults provides default values for xconfig
Package defaults provides default values for xconfig
defaults
Package defaults provides default values for xconfig
Package defaults provides default values for xconfig
env
Package env provides environment variables support for xconfig
Package env provides environment variables support for xconfig
flag
Package flag provides flags support for xconfig
Package flag provides flags support for xconfig
loader
Package file provides config loader support for xconfig
Package file provides config loader support for xconfig
secret
Package secret enable xconfig to integrate with secret plugins.
Package secret enable xconfig to integrate with secret plugins.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL