config

package module
v1.1.1 Latest Latest
Warning

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

Go to latest
Published: May 29, 2026 License: MIT Imports: 9 Imported by: 0

README

Ayotl

Ayotl is a lightweight Go library for loading configuration. It supports config files (JSON / YAML / INI), environment variable placeholders within those files, and environment-only mode for when no config file is needed — without forcing you to implement any interface.

import "github.com/beabys/ayotl"

Quick Start

// 1. Define your config struct with mapstructure tags
type ServerConfig struct {
	Host string `mapstructure:"host"`
	Port int    `mapstructure:"port"`
}
type Config struct {
	Server ServerConfig `mapstructure:"server"`
}
//                                                 
// 2. Create a new config, load from file, unmarshal
cfg := config.New().WithEnv().LoadConfigs("config.json")
cfg.Unmarshal(&myConfig)

No struct methods to implement. No interface to satisfy. Just set fields on config.Config and call load.


Modes

1. Config File Mode — JSON / YAML / INI

Load values from a .json, .yaml, .yml, or .ini file:

cfg := config.New().
    WithEnv().
    LoadConfigs("config.json")

Config files support optional ${PLACEHOLDER} substitution. Use WithEnv() to load env vars for placeholder resolution:

{
    "stage": "${STAGE}",
    "app": {
        "host": "127.0.0.1",
        "port": "${APP_PORT}"
    }
}
cfg := config.New().
    WithEnv().
    LoadConfigs("config.json")
// stage = os.Getenv("STAGE"), app.port = os.Getenv("APP_PORT")

Restrict which env vars are available for substitution for security:

cfg := config.New().
    WithEnv("STAGE", "APP_PORT").  // ← only these two
    LoadConfigs("config.json")

If a referenced placeholder is not set (or filtered out), it resolves to empty string.


2. Environment-Only Mode — no files

Call LoadConfigs() with no arguments. Env vars are loaded into ConfigMap via an explicit alias:

cfg := config.New()
cfg.EnvAlias = config.ConfigEnvAlias{
    "SERVER_HOST": "server.host",
    "SERVER_PORT": "server.port",
}
cfg.WithEnv().LoadConfigs()

fmt.Println(cfg.MustString("server.host", ""))  // "localhost"

EnvAlias maps env var names to dot-notation config keys. Only env vars listed in the alias are placed into ConfigMap.

Note: LoadConfigs() calls WithEnv() internally if env vars haven't been loaded yet, so you can omit the explicit WithEnv() call:

cfg := config.New()
cfg.EnvAlias = config.ConfigEnvAlias{
    "SERVER_HOST": "server.host",
}
cfg.LoadConfigs()  // ← WithEnv called internally

Default Values

Set fallback values via the Defaults field. Defaults are applied before env alias overrides, so env vars always take precedence:

cfg := config.New()
cfg.Defaults = config.ConfigMap{
    "server.host":   "127.0.0.1",
    "server.port":   3000,
    "logger.level":  "info",
}
cfg.LoadConfigs()

Defaults and env alias can be combined freely. Env vars that match an alias key override the default. Keys not set by env keep their default.


Constructor: NewWithParams

Batch-set Defaults and EnvAlias at construction time:

cfg := config.NewWithParams(&config.Params{
    Defaults: config.ConfigMap{
        "server.port":  9090,
        "logger.level": "info",
    },
    EnvAlias: config.ConfigEnvAlias{
        "SERVER_HOST": "server.host",
        "SERVER_PORT": "server.port",
    },
})
cfg.WithEnv().LoadConfigs()

NewWithParams does not modify ConfigMap or EnvConfigMap — it only sets Defaults and EnvAlias. Loading still happens when you call LoadConfigs().


Immutability

Lock the config after loading to prevent accidental mutations at runtime:

cfg := config.New()
cfg.Defaults = config.ConfigMap{"server.host": "original"}
cfg.LoadConfigs()

cfg.Immutable()

// All mutations become no-ops:
cfg.Set("server.host", "will-not-stick")
cfg.SetConfigMap(newMap)
cfg.WithEnv("SOME_SECRET")

Immutable() can be called before LoadConfigs() — loading still works (env vars and defaults are applied), but all post-load writes are blocked:

cfg := config.New()
cfg.EnvAlias = config.ConfigEnvAlias{
    "SERVER_HOST": "server.host",
}
cfg.Immutable().
    LoadConfigs()         // ← still works

cfg.Set("server.host", "blocked")  // ← no-op

After Immutable(), only Get, Must*, and Unmarshal remain available.


Unmarshal

After loading, decode the resolved ConfigMap into your typed struct:

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

var myConfig Config
cfg := config.New().WithEnv().LoadConfigs("config.json")
if err := cfg.Unmarshal(&myConfig); err != nil {
    log.Fatal(err)
}
fmt.Println(myConfig.Server.Host)

All fields need mapstructure struct tags to be recognized.


Access values directly

Use the Must* helpers to read values by dot-notation key:

host  := cfg.MustString("server.host", "localhost")
port  := cfg.MustInt("server.port", 3000)
debug := cfg.MustBool("server.debug", false)

Must* checks EnvConfigMap first (env vars loaded by WithEnv), then falls back to ConfigMap. If neither has the key, the default value is returned.


Struct tag requirement

All configurable fields must have a mapstructure struct tag. Fields without a tag are ignored in both file and env-only modes.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Flatten

func Flatten(m map[string]interface{}) map[string]interface{}

Flatten is a init wrapper for flatten

func GetValue

func GetValue(m map[string]interface{}, keysToFind []string) interface{}

GetValue is a function to search recursively a key in a map[string]interface{}

func MergeEnvVar

func MergeEnvVar(m, envVars ConfigMap) map[string]interface{}

MergeEnvVar merge Env variables into placeholders

func MergeKeys

func MergeKeys(m1, m2 ConfigMap) map[string]interface{}

MergeKeys merge 2 ConfigMap given

func SetValue

func SetValue(m map[string]interface{}, keysToFind []string, value interface{}) map[string]interface{}

SetValue is a function to search recursively a key in a map[string]interface{} and add it with a set of keys given

Types

type Config

type Config struct {
	ConfigMap    ConfigMap
	EnvConfigMap ConfigMap
	Defaults     ConfigMap
	EnvAlias     ConfigEnvAlias
	// contains filtered or unexported fields
}

func New

func New() *Config

New returns a new Config instance with empty ConfigMap and EnvConfigMap.

func NewWithParams added in v1.1.0

func NewWithParams(params *Params) *Config

NewWithParams returns a new Config instance with provided defaults and env alias.

func (*Config) ConfigFileMerge

func (c *Config) ConfigFileMerge(s string) error

ConfigFileMerge read configs from file and merge the config into ConfigMap if Key exist previosly in ConfigMap, the value will be overridden by the value from the file

func (*Config) Get

func (c *Config) Get(k string) interface{}

Get return value from given key, and return empty string if key don't exist key can be passed in `dot-notation`

func (*Config) Immutable added in v1.0.0

func (c *Config) Immutable() *Config

Immutable prevents any future mutation to the Config. After calling Immutable, Set, SetConfigMap, ConfigFileMerge, and WithEnv become no-ops. LoadConfigs still works when called after Immutable — it uses internal write paths to apply defaults and env vars.

func (*Config) LoadConfigs

func (c *Config) LoadConfigs(configFiles ...string) (err error)

LoadConfig is a function to load the configurations in ConfigMap from the provided config files, and merge with env variables if exist If no config files provided, apply defaults + env alias overrides This is a convenience method that calls LoadConfigs with the provided files.

func (*Config) MustBool

func (c *Config) MustBool(key string, must bool) bool

MustBool returns the value associated with the key as a int64 or a default value if 0.

func (*Config) MustEnvString

func (c *Config) MustEnvString(key, must string) string

MustString returns the value associated with the key as a string or a default value if empty string.

func (*Config) MustInt

func (c *Config) MustInt(key string, must int) int

MustInt returns the value associated with the key int or a default value if 0.

func (*Config) MustInt32

func (c *Config) MustInt32(key string, must int32) int32

MustInt32 returns the value associated with the key as a int32 or a default value if 0.

func (*Config) MustInt64

func (c *Config) MustInt64(key string, must int64) int64

MustInt64 returns the value associated with the key as a int64 or a default value if 0.

func (*Config) MustString

func (c *Config) MustString(key, must string) string

MustString returns the value associated with the key as a string or a default value if empty string.

func (*Config) Set

func (c *Config) Set(k string, v interface{})

Set add or update value from given key. key can be passed in `dot-notation`. If Immutable() has been called, Set is a no-op.

func (*Config) SetConfigMap

func (c *Config) SetConfigMap(cm ConfigMap) *Config

SetConfigMap sets the entire ConfigMap. If the Config is immutable, this is a no-op.

func (*Config) Unmarshal

func (c *Config) Unmarshal(s any) error

Unmarshal function convert a ConfigMap type into a struct using mapStructure Decoder

func (*Config) WithEnv

func (c *Config) WithEnv(envs ...string) *Config

WithEnv Load env variables and add into ConfigMap

type ConfigEnvAlias added in v1.1.0

type ConfigEnvAlias map[string]string

type ConfigMap

type ConfigMap map[string]interface{}

func ReadFile

func ReadFile(file string) (ConfigMap, error)

ReadFile is a function to read a file and decode, supporting only yaml and json at the moment

type Params added in v1.1.0

type Params struct {
	Defaults ConfigMap
	EnvAlias ConfigEnvAlias
}

Jump to

Keyboard shortcuts

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