API Reference

Complete reference for confkit's public Go API.

func

Load

func Load[T any](sources ...Source) (*T, error)

Loads configuration from the provided sources and returns a pointer to a fully typed, validated config, or an error.

ParameterTypeDescription
sources...SourceVariable number of Source instances to load from

Returns

  • *T — Pointer to the configuration struct (nil on error)
  • error — An *ErrorReport if validation fails

Example

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

cfg, err := confkit.Load[Config](
    confkit.FromEnv(),
)
if err != nil {
    log.Fatal(confkit.Explain(err))
}
// cfg is *Config; field access works normally: cfg.Port
func

LoadWithOptions

func LoadWithOptions[T any](options ...Option) (*T, error)

Advanced loading with functional options for custom validators, middleware, and interpolation configuration.

Options

OptionDescription
WithSource(source Source)Add a configuration source
WithValidator(name, fn)Register a custom per-field validator
WithModelValidator[T](fn)Register a cross-field validator
WithMiddleware(fn)Add a value transformation middleware
WithInterpolationMaxDepth(n)Set interpolation recursion limit
WithAuditLogger(fn)Receive a log of every field's resolved value and source
WithLoadHook(fn)Receive success/duration/errCount after every load

Example

cfg, err := confkit.LoadWithOptions[Config](
    confkit.WithSource(confkit.FromYAML("config.yaml")),
    confkit.WithSource(confkit.FromEnv()),
    // Cross-field validation
    confkit.WithModelValidator(func(cfg *Config) error {
        if cfg.TLSEnabled && cfg.CertPath == "" {
            return fmt.Errorf("cert_path required when tls_enabled is true")
        }
        return nil
    },
    // Audit trail
    confkit.WithAuditLogger(func(entries []confkit.AuditEntry) {
        for _, e := range entries {
            log.Printf("field=%s source=%s value=%s", e.Field, e.Source, e.Value)
        }
    },
)
func

LoadWithWatcher

func LoadWithWatcher[T any](filePath string, sources ...Source) (*T, *ConfigWatcher, error)

Loads configuration and returns a pointer to the config and a watcher for hot-reloading when files change.

ParameterTypeDescription
filePathstringPath to watch for changes
sources...SourceConfiguration sources

Returns

  • *T — Pointer to initial configuration struct
  • *ConfigWatcher — Watcher instance for subscribing to changes
  • error — Load or watcher creation error

Example

cfg, watcher, err := confkit.LoadWithWatcher[Config](
    "config.yaml",
    confkit.FromEnv(),
    confkit.FromYAML("config.yaml"),
)

watcher.AddListener(func(oldCfg, newCfg any, err error) {
    if err != nil {
        log.Printf("Reload failed: %v", err)
        return
    }
    log.Println("Config reloaded")
})
watcher.Start()
func

Explain

func Explain(err error) string

Formats an error report into a human-readable, colorized error message suitable for logging or stdout.

Example

cfg, err := confkit.Load[Config](confkit.FromEnv())
if err != nil {
    fmt.Println(confkit.Explain(err))
    // Invalid configuration:
    // 
    //   PORT
    //     error: must be between 1 and 65535
    //     got: 99999
    //     source: env (PORT)
}
func

LoadContext

func LoadContext[T any](ctx context.Context, sources ...Source) (*T, error)

Context-aware variant of Load. Propagates deadlines and cancellation to cloud sources.

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

cfg, err := confkit.LoadContext[Config](ctx,
    vault.FromVault("https://vault.example.com", auth, "/secret/app"),
    confkit.FromEnv(),
)
func

MustLoad

func MustLoad[T any](sources ...Source) *T

Like Load but panics on error. Intended for use in main() where a config failure is unrecoverable.

cfg := confkit.MustLoad[Config](confkit.FromEnv(), confkit.FromYAML("config.yaml"))
func

ValidateOnly

func ValidateOnly[T any](sources ...Source) error

Dry-run: loads and validates configuration without returning the struct or producing side effects. Useful in pre-flight checks and CI.

if err := confkit.ValidateOnly[Config](confkit.FromEnv()); err != nil {
    fmt.Fprintln(os.Stderr, confkit.Explain(err))
    os.Exit(1)
}
func

Dump / DumpString / DumpYAML

func Dump[T any](cfg *T, opts ...DumpOption) ([]byte, error)
func DumpString[T any](cfg *T, opts ...DumpOption) (string, error)
func DumpYAML[T any](cfg *T, opts ...DumpOption) (string, error)

Serialize the loaded config with all secret:"true" fields automatically redacted. Safe to log or write to files.

OptionDescription
WithDumpFormat(format)Output format: "json" (default), "yaml", "toml"
WithDumpRedactSecrets(bool)Toggle redaction (default: true)
cfg, _ := confkit.Load[Config](confkit.FromEnv())

s, _ := confkit.DumpString[Config](cfg)
log.Println(s) // {"Port":8080,"Password":"***REDACTED***"}

y, _ := confkit.DumpYAML[Config](cfg)
log.Println(y)
func

FindFile / FindSource

func FindFile(name string, dirs ...string) (string, error)
func FindSource(name string, dirs ...string) (Source, error)
func DefaultSearchDirs() []string

Locate a config file by base name with automatic extension fallback (.yaml.yml.json.toml). ErrNotFound is returned as a sentinel when no file is found.

path, err := confkit.FindFile("config", confkit.DefaultSearchDirs()...)
if errors.Is(err, confkit.ErrNotFound) {
    // proceed with defaults only
}

// Or resolve to a Source directly:
src, err := confkit.FindSource("config", ".", "/etc/myapp")

Sources

source

FromEnv

func FromEnv() Source

Loads configuration from environment variables. Field names are uppercased and matched to env tags.

type Config struct {
    DatabaseURL string `env:"DATABASE_URL" validate:"required"`
    Port        int    `env:"PORT" default:"8080"`
}

// Reads from $DATABASE_URL and $PORT
cfg, _ := confkit.Load[Config](confkit.FromEnv())
source

FromYAML

func FromYAML(path string) Source

Loads configuration from a YAML file.

// config.yaml:
// databaseURL: postgres://localhost/db
// port: 3000

cfg, _ := confkit.Load[Config](confkit.FromYAML("config.yaml"))
source

FromJSON

func FromJSON(path string) Source

Loads configuration from a JSON file.

cfg, _ := confkit.Load[Config](confkit.FromJSON("config.json"))
source

FromTOML

func FromTOML(path string) Source

Loads configuration from a TOML file.

cfg, _ := confkit.Load[Config](confkit.FromTOML("config.toml"))
source

FromYAMLFiles / FromJSONFiles / FromTOMLFiles

func FromYAMLFiles(paths ...string) Source
func FromJSONFiles(paths ...string) Source
func FromTOMLFiles(paths ...string) Source

Merges multiple files of the same format into a single source. First file to provide a value wins; later files fill in only unset fields. Nested maps are deep-merged.

cfg, _ := confkit.Load[Config](
    confkit.FromYAMLFiles("base.yaml", "production.yaml", "local.yaml"),
    confkit.FromEnv(),
)
source

FromYAMLOptional

func FromYAMLOptional(path string) Source

Like FromYAML but silently skips missing files instead of returning an error. Useful for optional local override files.

cfg, err := confkit.Load[Config](
    confkit.FromYAML("config.yaml"),           // required base config
    confkit.FromYAMLOptional("config.local.yaml"), // dev overrides (git-ignored)
    confkit.FromEnv(),
)
source

FromOverlay

func FromOverlay(baseName string) Source
func OverlayPath(baseName, env string) string

Spring Boot-style environment layering. Loads baseName.yaml as base, then overlays baseName-{env}.yaml on top, where the env name is read from the APP_ENV / ENV environment variable.

// APP_ENV=prod loads: config.yaml + config-prod.yaml
cfg, err := confkit.Load[Config](
    confkit.FromOverlay("config"),
    confkit.FromEnv(),
)
source

FromFlags

func FromFlags() Source

Loads configuration from command-line flags. Field names are converted to kebab-case flags.

Supported flag formats

  • --key=value — long flag with = separator
  • --key value — long flag with space separator
  • -k value — short flag with space separator
  • -k=value — short flag with = separator
  • --flag — boolean flag (sets field to "true")
// Run: go run main.go --database-url=... --port=3000 --verbose
cfg, _ := confkit.Load[Config](confkit.FromFlags())

Cloud & Enterprise Sources

cloud

FromKubernetesConfigMap

import "github.com/MimoJanra/confkit/k8s"

// go get github.com/MimoJanra/confkit/k8s@latest

func FromKubernetesConfigMap(namespace, configMapName string) confkit.Source
func FromKubernetesConfigMapWithPath(namespace, configMapName, mountPath string) confkit.Source

Loads configuration from a Kubernetes ConfigMap. Use FromKubernetesConfigMapWithPath when the ConfigMap is mounted at a custom path instead of the in-cluster API.

// in-cluster API
cfg, err := confkit.Load[Config](
    k8s.FromKubernetesConfigMap("default", "app-config"),
)

// mounted volume at custom path
cfg, err = confkit.Load[Config](
    k8s.FromKubernetesConfigMapWithPath("default", "app-config", "/etc/config"),
)
cloud

FromAWSSSMParameterStore

import "github.com/MimoJanra/confkit/aws"

// go get github.com/MimoJanra/confkit/aws@latest

func FromAWSSSMParameterStore(parameterPath string) confkit.Source
func FromAWSSSMParameterStoreMultiRegion(pathPrefix string, regions []string) confkit.Source

Loads configuration from AWS Systems Manager Parameter Store. The multi-region variant fails over across regions automatically.

cfg, err := confkit.Load[Config](
    aws.FromAWSSSMParameterStore("/prod/app/config"),
)

// multi-region failover
cfg, err = confkit.Load[Config](
    aws.FromAWSSSMParameterStoreMultiRegion("/prod/app/config", []string{"us-east-1", "us-west-2"}),
)
cloud

FromVault

import "github.com/MimoJanra/confkit/vault"

// go get github.com/MimoJanra/confkit/vault@latest

func FromVault(addr string, auth vault.VaultAuth, pathPrefix string) confkit.Source
func FromVaultWithKVVersion(addr string, auth vault.VaultAuth, kvVersion int, pathPrefix string) confkit.Source

Loads secrets from HashiCorp Vault KV store. FromVault defaults to KV v2. Use FromVaultWithKVVersion to explicitly select KV v1 (kvVersion=1) or v2 (kvVersion=2).

Auth methods

vault.VaultTokenAuth(token string) vault.VaultAuth
vault.VaultAppRoleAuth(roleID, secretID string) vault.VaultAuth
vault.VaultKubernetesAuth(role, jwt string) vault.VaultAuth
auth := vault.VaultTokenAuth(os.Getenv("VAULT_TOKEN"))

cfg, err := confkit.Load[Config](
    vault.FromVault("https://vault.example.com", auth, "/secret/myapp"),
)

// KV v1 explicit
cfg, err = confkit.Load[Config](
    vault.FromVaultWithKVVersion("https://vault.example.com", auth, 1, "/secret/myapp"),
)
cloud

FromConsulWithOptions

import "github.com/MimoJanra/confkit/consul"

// go get github.com/MimoJanra/confkit/consul@latest

func FromConsul(addr string) confkit.Source
func FromConsulWithToken(addr, token string) confkit.Source
func FromConsulWithOptions(addr, token, datacenter string) confkit.Source

Loads configuration from Consul KV store. Use FromConsulWithOptions for full control (addr, token, datacenter). Use FromConsulWithToken for authenticated access without datacenter selection. Use FromConsul for unauthenticated access.

cfg, err := confkit.Load[Config](
    consul.FromConsulWithOptions("consul.example.com:8500", "token", "dc1"),
)
cloud

FromEtcdWithPrefix

import "github.com/MimoJanra/confkit/etcd"

// go get github.com/MimoJanra/confkit/etcd@latest

func FromEtcd(endpoints []string) confkit.Source             // prefix: /myapp/
func FromEtcdWithPrefix(endpoints []string, prefix string) confkit.Source

Loads configuration from etcd v3 key-value store under the given key prefix.

cfg, err := confkit.Load[Config](
    etcd.FromEtcdWithPrefix(
        []string{"etcd1.example.com:2379", "etcd2.example.com:2379"},
        "/myapp",
    ),
)
cloud

FromAWSSecretsManager

func FromAWSSecretsManager(secretName string) confkit.Source
func FromAWSSecretsManagerMultiRegion(secretName string, regions []string) confkit.Source

Loads secrets from AWS Secrets Manager with automatic rotation support. The multi-region variant fails over across regions with health tracking.

cfg, err := confkit.Load[Config](
    aws.FromAWSSecretsManager("prod/app-secrets"),
)

// multi-region failover
cfg, err = confkit.Load[Config](
    aws.FromAWSSecretsManagerMultiRegion("prod/app-secrets", []string{"us-east-1", "eu-west-1"}),
)

Observability

pkg

confkit/prometheus

import "github.com/MimoJanra/confkit/prometheus"

// go get github.com/MimoJanra/confkit/prometheus@latest

m := prometheus.NewMetrics(prometheus.DefaultRegisterer)

cfg, err := confkit.LoadWithOptions[Config](
    confkit.WithSource(confkit.FromEnv()),
    m.Hook(),
)

Metrics registered

  • confkit_loads_total{"status":"success|error"} — counter
  • confkit_load_duration_seconds — histogram
  • confkit_errors_total{"kind":"validation"} — counter
pkg

confkit/otel

import "github.com/MimoJanra/confkit/otel"

// go get github.com/MimoJanra/confkit/otel@latest

func Load[T any](ctx context.Context, tracer trace.Tracer, sources ...confkit.Source) (*T, error)
func LoadWithOptions[T any](ctx context.Context, tracer trace.Tracer, options ...confkit.Option) (*T, error)

Wraps LoadContext / LoadWithOptionsContext with an OpenTelemetry span. Both functions propagate the span context to cloud sources.

cfg, err := otel.Load[Config](ctx, tracer,
    confkit.FromEnv(),
    confkit.FromYAML("config.yaml"),
)
// Creates span "confkit.Load" with attributes:
// confkit.sources, confkit.success

Types

type

ErrorReport

The error type returned by Load(). Implements the error interface.

type ErrorReport struct {
    Errors []FieldError
}

func (e *ErrorReport) Error() string
func (e *ErrorReport) AddError(err FieldError)
func (e *ErrorReport) IsEmpty() bool
func (e *ErrorReport) Unwrap() []error
func (e *ErrorReport) Format() string
func (e *ErrorReport) FirstError() *FieldError
type

FieldError

Represents a single field validation or loading error.

type FieldError struct {
    Path    string
    Source  string
    Kind    ErrorKind  // parse | validation | io
    Rule    string
    Message string
    Value   string
    Secret  bool
}
type

Source

Interface for configuration sources. Implement to create custom sources.

type Source interface {
    Name() string
    Lookup(ctx context.Context, field *FieldInfo) (any, bool, error)
}

Custom Source Example

type MySource struct{}

func (s *MySource) Name() string { return "custom" }

func (s *MySource) Lookup(ctx context.Context, field *FieldInfo) (any, bool, error) {
    return "value", true, nil
}

cfg, _ := confkit.Load[Config](&MySource{})
type

ConfigDelta

Describes which fields changed between two config reloads. Returned by AddDeltaListener.

type ConfigDelta struct {
    Changed []FieldChange
}

type FieldChange struct {
    Path     string
    OldValue any
    NewValue any
    Secret   bool
}

AddDeltaListener

func (w *ConfigWatcher) AddDeltaListener(fn func(*T, *T, *ConfigDelta, error))

Like AddListener but also provides a ConfigDelta with the list of changed fields, enabling targeted reactions to specific field changes.

watcher.AddDeltaListener(func(old, new *Config, delta *confkit.ConfigDelta, err error) {
    if err != nil { return }
    for _, ch := range delta.Changed {
        log.Printf("field %s changed", ch.Path)
    }
})

Struct Tags & Validation

Struct Tags

Configuration is driven by struct tags. All tags are optional.

TagPurposeExample
envEnvironment variable nameenv:"DATABASE_URL"
yaml / jsonFile field nameyaml:"database_url"
defaultDefault value if not founddefault:"localhost"
validateValidation rules (comma-separated)validate:"required,min=1,max=65535"
secretMark as sensitive — auto-redactedsecret:"true"
descHelp text / descriptiondesc:"Database connection URL"
flagCLI long flag nameflag:"database-url"
shortCLI short flag (single char)short:"d"
prefixPrefix for nested struct env varsprefix:"DB_"

Complete Example

type DatabaseConfig struct {
    Host     string `env:"DB_HOST" default:"localhost"`
    Port     int    `env:"DB_PORT" validate:"min=1,max=65535" default:"5432"`
    Username string `env:"DB_USER" validate:"required"`
    Password string `env:"DB_PASSWORD" validate:"required" secret:"true"`
}

type Config struct {
    Database DatabaseConfig
    LogLevel string `env:"LOG_LEVEL" validate:"oneof=debug,info,warn,error" default:"info"`
}

Validation Rules

All built-in validation rules — no external library required.

Presence & Range

RuleDescription
requiredField must be present and non-zero
min=NMinimum value (int/float) or minimum length (string)
max=NMaximum value (int/float) or maximum length (string)
oneof=a,b,cMust be one of the listed values
notemptyMust not be blank (non-whitespace)

Format Validators

RuleDescription
emailValid email address
urlValid URL (any scheme)
http_urlValid HTTP or HTTPS URL
ipValid IPv4 or IPv6 address
ipv4Valid IPv4 address
ipv6Valid IPv6 address
uuidValid UUID (v1–v5)
hostnameValid hostname per RFC 1123
portValid port number 1–65535 (int or string)
regex=patternMust match the regular expression

String Validators

RuleDescription
len=NMust be exactly N characters (Unicode-aware)
contains=strMust contain the substring
startswith=strMust start with the prefix
endswith=strMust end with the suffix
alphaLetters only
alphanumLetters and digits only
numericDigits only
lowercaseMust be all lowercase
uppercaseMust be all uppercase

Example

type Config struct {
    Port        int    `env:"PORT"    validate:"required,port"`
    AdminEmail  string `env:"EMAIL"   validate:"required,email"`
    APIKey      string `env:"API_KEY" validate:"required,len=32" secret:"true"`
    Environment string `env:"ENV"     validate:"oneof=dev,staging,prod"`
    ServiceURL  string `env:"SVC_URL" validate:"http_url"`
    ServiceID   string `env:"SVC_ID"  validate:"uuid"`
}