config

package
v1.10.1 Latest Latest
Warning

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

Go to latest
Published: Jun 11, 2026 License: BSD-3-Clause Imports: 14 Imported by: 0

Documentation

Overview

Package config provides a simple, structured, and extensible way to manage application configuration in Go.

It builds upon the Viper library and adds powerful features like validation, default value registration, environment and flag integration, and structured config registration.

Key Features:

  • Register typed configuration structs with default values.
  • Parse YAML configuration files and bind fields to CLI flags and environment variables.
  • Automatically generate flags based on struct field tags.
  • Validate configuration using custom logic (via `Validate()` method).
  • Write current configuration back to disk and trigger onChange handlers.
  • Load configuration from disk on each Read() call.
  • Automatically fallbacks to default config creation if no file is found.

All configuration structs must implement the `Config` interface:

type Config interface {
    Validate() error
}

Example:

package config

import (
    "fmt"
    "github.com/valentin-kaiser/go-core/config"
    "github.com/valentin-kaiser/go-core/flag"
)

type ServerConfig struct {
    Host string `yaml:"host" usage:"The host of the server"`
    Port int    `yaml:"port" usage:"The port of the server"`
}

func (c *ServerConfig) Validate() error {
    if c.Host == "" {
        return fmt.Errorf("host cannot be empty")
    }
    if c.Port <= 0 {
        return fmt.Errorf("port must be greater than 0")
    }
    return nil
}

func Get() *ServerConfig {
    c, ok := config.Get().(*ServerConfig)
    if !ok {
        return &ServerConfig{}
    }
    return c
}

func init() {
    cfg := &ServerConfig{
        Host: "localhost",
        Port: 8080,
    }

    // Register config - path parameter is ignored, flag.Path will be used
    if err := config.Register("", "server", cfg); err != nil {
        fmt.Println("Error registering config:", err)
        return
    }

    // Parse flags (including --path and config-specific flags)
    flag.Init()

    // Read config using the parsed --path flag - loads from disk each time
    if err := config.Read(); err != nil {
        fmt.Println("Error reading config:", err)
        return
    }

    // Register onChange handler to be called when Write() is used
    config.OnChange(func(o, n config.Config) error {
        fmt.Println("Configuration changed")
        return nil
    })

    // Update configuration - this will trigger onChange handlers
    if err := config.Write(cfg); err != nil {
        fmt.Println("Error writing config:", err)
    }
}

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = errors.New("configuration not found")

ErrNotFound is returned by a Source when the requested configuration does not yet exist in the backing store. When Read() encounters this from the base source, it bootstraps the source by saving the current default configuration and then loads it again.

View Source
var ErrReadOnly = errors.New("configuration source is read-only")

ErrReadOnly may be returned by a Source from Save to indicate that the underlying store does not support writes. Manager.Write treats this as a non-fatal condition for overlays but as fatal for the base source.

View Source
var ErrWatchUnsupported = errors.New("configuration source does not support watch")

ErrWatchUnsupported may be returned by a Source from Watch to indicate that the underlying store does not support change notifications. StartWatch silently skips sources that return this error.

Functions

func Changed

func Changed(o, n any) bool

Changed checks if two configuration values are different by comparing their reflection values. It returns true if the configurations differ, false if they are the same. This function handles nil values correctly and performs deep comparison of the underlying values.

func Manager added in v1.5.3

func Manager() *manager

Manager returns the singleton configuration manager instance

func OnChange

func OnChange(f func(o Config, n Config) error)

OnChange registers a function that is called when the configuration changes

func Read

func Read() error

Read loads the configuration from the configured sources, validates it and applies it. The base source is consulted first; any registered overlays are then merged on top. When the base source reports that no configuration exists yet (ErrNotFound), the current in-memory defaults are persisted and the source is loaded again. Read always reloads from the sources; values are never cached across calls.

func Reset

func Reset()

Reset clears the config package state Everything must be re-registered after calling this function

func StartWatch added in v1.10.0

func StartWatch(ctx context.Context) error

StartWatch subscribes to change notifications from the base source and all overlays that support them. When any watched source reports a change, the configuration is reloaded and OnChange handlers are invoked. Sources that return ErrWatchUnsupported are silently skipped. Call StopWatch to stop watching. StartWatch is safe to call multiple times; previous watches are cancelled first.

func StopWatch added in v1.10.0

func StopWatch()

StopWatch cancels any active watches started via StartWatch.

func Write

func Write(change Config) error

Write persists the configuration to the base source, validates it and applies it in memory. OnChange handlers are triggered with the previous and new configuration. If the base source is read-only, an error is returned.

Types

type Config

type Config interface {
	Validate() error
}

Config is the interface that all configuration structs must implement It should contain a Validate method that checks the configuration for errors

func Get

func Get() Config

Get returns the current configuration

type Source added in v1.10.0

type Source interface {
	// Name returns a short, human readable identifier of the source used in
	// log and error messages (e.g. "file", "etcd").
	Name() string

	// Load returns the full set of configuration values as a flat map keyed
	// by lower-case dotted paths (e.g. "server.port"). Implementations must
	// return ErrNotFound if the configuration has not been initialised yet.
	Load(ctx context.Context) (map[string]interface{}, error)

	// Save persists the given configuration. Implementations that are
	// read-only must return ErrReadOnly.
	Save(ctx context.Context, c Config) error

	// Watch subscribes to changes in the source. The callback is invoked with
	// the freshly loaded values on every change. The returned cancel function
	// stops the watch. Implementations that do not support watching must
	// return ErrWatchUnsupported.
	Watch(ctx context.Context, onChange func(map[string]interface{})) (cancel func(), err error)
}

Source abstracts the backing store of a configuration. Built-in sources include a YAML file source (the default) and the etcd source provided by the etcd package. Custom sources may implement this interface to plug additional stores (Consul, Vault, HTTP endpoints, ...).

All methods are invoked from the manager goroutine and may be called concurrently with Watch callbacks; implementations must be safe for use by multiple goroutines.

Jump to

Keyboard shortcuts

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