mflag

package module
v0.0.2-0...-b5136fd Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2025 License: MIT Imports: 9 Imported by: 0

README

mflag

Go Reference Go Report Card

Go library that integrates config loading from YAML files and Go flags.

mflag was implemented based on a typical workflow for apps running in Kubernetes:

  • In production, read configs from a configmap YAML file
  • In staging, read default configs
  • In local, read default configs with the option of overriding them via CLI flags, for ease of debugging.

✨ Features

  • Simple, Declarative API - Define defaults, load a file, and parse. That's it.
  • Automatic Command-line Flags - Every configuration key is automatically available as a command-line flag for overrides.
  • YAML configuration support - Load defaults from config files
  • Clear precedence order - Command-line flags > Config file > Code defaults
  • Minimal dependencies - Only requires YAML parsing

🚀 Quick Start

go get github.com/ndealmeida/mflag

main.go:

package main

import (
    "fmt"
    "log"

    "github.com/ndealmeida/mflag"
)

func defaults() {
    mflag.SetDefault("debug", true)
    mflag.SetDefault("port", 3000)
    mflag.SetDefault("database.host", "localhost")
    mflag.SetDefault("database.port", 5432)
    mflag.SetDefault("database.name", "myapp")
}

func main() {
    defaults()
    if err := mflag.Init("configmap.yaml"); err != nil {
        log.Fatalf("Error loading config: %v", err)
    }
    mflag.Parse()

    // Print all flags
    if mflag.GetBool("debug") {
        mflag.Debug()
    }
}

configmap.yaml:

port: 3000
debug: false
database:
  host: "localhost"
  port: 5432
  name: "myapp"

You can override any config via CLI:

go run main.go --help
go run main.go --port=8080

📚 Good to know

Reading from yaml is optional and won't return an error if the file doesn't exist. Hence it is a good practise to always provide safe defaults.

Values are resolved in this order (highest to lowest priority):

  1. Command-line flags - Explicit user input (highest priority)
  2. YAML configuration file - Persistent settings
  3. Default values in code - Fallback values

After calling mflag.Parse(), you can retrieve values by key:

mflag.Parse()

// Get typed values
port := mflag.GetInt("port")
debug := mflag.GetBool("debug")

// Use dot-notation to access nested values
host := mflag.GetString("database.host")

// or via map if there are several keys within the map 
// and they all have string values
dbKey := mflag.GetStringMapString("database")
host = dbKey["host"]

// Check if a value was explicitly set
if mflag.IsSet("port") {
    fmt.Println("Port was explicitly configured")
}

Check example for a practical example of parsing configs into a struct. In bigger applications, you may want to split AppConfig into multiple configs like DBConfig, CacheConfig, etc.

🔧 Trade-offs

This library is for you if you want a lightweight and ergonomic API. This library is NOT for you if you require strong config validation at every step, and relying on sane defaults is not an option for your use case. See the examples below:

Init() error handling

As mentioned above, we deliberately chose to not return an error when the config YAML file is not found. This allows an application to run with defaults locally without needing a config file. In any other case, such as a file with wrong permissions or invalid YAML syntax, Init() will return a descriptive error.

Get* error handling

This library prioritizes ease of use over forcing error checks on every value retrieval. In the example above:

port := mflag.GetInt("port")
host := mflag.GetString("host")
debug := mflag.GetBool("debug")

When the flag was not found, Get* functions return their zero value. If we would have opted for a stronger validation, we would need to check errors in every single line of loading each config, which would be verbose and tedious.

Parse() error handling

Parse() does not return an error, to be consistent with the flag package from the standard library. It is designed for simplicity in common use cases. If an error occurs during parsing (e.g., an invalid value in a config file), Parse() will print the error message and exit the application, mirroring the default behavior of flag.Parse().

Loading configurations is often the first thing an application does, so this is generally an acceptable approach. However if you open connections or spin up go routines before loading configs, exiting won't gracefully shutdown your application. For those cases you can use ParseWithError(). This function performs the same logic as Parse() but returns an error on failure instead of exiting.

Note: calling any Get* function before Parse() or ParseWithError() will cause a panic. This is a deliberate design choice to prevent silent failures from incorrect library usage, distinguishing a programmer error (violating the library's lifecycle) from a runtime error (bad input data).

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Documentation

Overview

Package mflag provides integrated configuration management for Go applications, merging settings from default values, YAML files, and command-line flags.

Example
defer func(oldArgs []string) {
	os.Args = oldArgs
	Reset()
}(os.Args)
Reset()

os.Args = []string{"cmd", "--host=flag.host", "--debug=false"}

SetDefault("host", "default.host")
SetDefault("port", 8080)
SetDefault("debug", true)
// Add default for a key that will not be overridden by config or flags
SetDefault("timeout", 5)

config.SetValue("host", "config.host")
config.SetValue("port", 9090)

Parse()

fmt.Printf("Host: %s (from flag)\n", GetString("host"))       // Highest precedence
fmt.Printf("Port: %d (from config)\n", GetInt("port"))        // Middle precedence
fmt.Printf("Debug: %t (from flag)\n", GetBool("debug"))       // Flag overriding default
fmt.Printf("Timeout: %d (from default)\n", GetInt("timeout")) // Lowest precedence
Output:

Host: flag.host (from flag)
Port: 9090 (from config)
Debug: false (from flag)
Timeout: 5 (from default)

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrInitFailed = errors.New("mflag: Init failed")
)

Functions

func AllKeys

func AllKeys() []string

AllKeys returns all keys in the config, flattened with dot notation. Must be called after Parse.

func Debug

func Debug()

Debug prints all configuration values to standard output. Must be called after Parse.

func GetBool

func GetBool(key string) bool

GetBool returns the value associated with the key as a boolean. Must be called after Parse.

func GetDuration

func GetDuration(key string) time.Duration

GetDuration returns the value associated with the key as a time.Duration. Must be called after Parse.

func GetFloat64

func GetFloat64(key string) float64

GetFloat64 returns the value associated with the key as a float64. Must be called after Parse.

func GetInt

func GetInt(key string) int

GetInt returns the value associated with the key as an integer. Must be called after Parse.

func GetInt16

func GetInt16(key string) int16

GetInt16 returns the value associated with the key as an int16. Must be called after Parse.

func GetInt32

func GetInt32(key string) int32

GetInt32 returns the value associated with the key as an int32. Must be called after Parse.

func GetInt64

func GetInt64(key string) int64

GetInt64 returns the value associated with the key as an int64. Must be called after Parse.

func GetInt8

func GetInt8(key string) int8

GetInt8 returns the value associated with the key as an int8. Must be called after Parse.

func GetString

func GetString(key string) string

GetString returns the value associated with the key as a string. It returns the final value after merging defaults, config file, and flags. Must be called after Parse.

func GetStringMapString

func GetStringMapString(key string) map[string]string

GetStringMapString returns the value associated with the key as a map of strings. Must be called after Parse.

func GetStringSet

func GetStringSet(key string) map[string]bool

GetStringSet returns the string slice value associated with a key as a map[string]bool (a set). This is useful for efficiently checking for the existence of an item in a list, like a feature flag. Must be called after Parse.

func GetStringSlice

func GetStringSlice(key string) []string

GetStringSlice returns the value associated with the key as a slice of strings. Must be called after Parse.

func GetUint

func GetUint(key string) uint

GetUint returns the value associated with the key as a uint. Must be called after Parse.

func GetUint16

func GetUint16(key string) uint16

GetUint16 returns the value associated with the key as a uint16. Must be called after Parse.

func GetUint32

func GetUint32(key string) uint32

GetUint32 returns the value associated with the key as a uint32. Must be called after Parse.

func GetUint64

func GetUint64(key string) uint64

GetUint64 returns the value associated with the key as a uint64. Must be called after Parse.

func GetUint8

func GetUint8(key string) uint8

GetUint8 returns the value associated with the key as a uint8. Must be called after Parse.

func Init

func Init(filename string) error

Init loads configuration from a YAML file at the given path. It should be called after setting defaults and before parsing flags.

func IsSet

func IsSet(key string) bool

IsSet checks if a key is set in the configuration. Must be called after Parse.

func Parse

func Parse()

Parse parses command-line arguments and merges all configuration sources. It MUST be called after setting defaults and calling Init. It dynamically creates command-line flags for all known configuration keys. Precedence: Flags > Config File > Defaults.

func ParseWithError

func ParseWithError() error

ParseWithError is similar to Parse but returns an error on failure. This allows for more granular error handling. Note: This function creates its own temporary flag set and does not parse flags defined globally via the standard `flag` package.

func Reset

func Reset()

func SetDefault

func SetDefault(key string, value interface{})

SetDefault sets a default value for a key. Defaults have the lowest precedence and are overridden by config files and flags. It should be called before Init and Parse.

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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