goconf

GoConf

A lightweight, flexible Go library for loading and validating environment-based configuration with beautiful output formatting.

Go Version License

Overview

GoConf simplifies configuration management in Go applications by providing:

Perfect for containerized applications, microservices, and cloud-native deployments where configuration is managed through environment variables following the 12-factor app methodology or structured YAML files.

Table of Contents

Installation

go get github.com/wgarunap/goconf

Quick Start

package main

import (
    "log"
    "github.com/wgarunap/goconf"
)

type Config struct {
    DatabaseURL string `env:"DATABASE_URL" validate:"required,uri"`
    Port        int    `env:"PORT" envDefault:"8080" validate:"gte=1024,lte=65535"`
    APIKey      string `env:"API_KEY" validate:"required" secret:"true"`
}

var AppConfig Config

func (Config) Register() error {
    return goconf.ParseEnv(&AppConfig)
}

func (Config) Validate() error {
    return goconf.StructValidator(AppConfig)
}

func (Config) Print() interface{} {
    return AppConfig
}

func main() {
    if err := goconf.Load(new(Config)); err != nil {
        log.Fatal(err)
    }

    log.Println("Configuration loaded successfully!")
}

Features

πŸ”§ Environment Variable Parsing

βœ… Built-in Validation

🎨 Multiple Output Formats

Table Format (Default)

Beautiful Unicode table output for development environments:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   CONFIG    β”‚          VALUE            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ DatabaseURL β”‚ postgres://localhost:5432 β”‚
β”‚ Port        β”‚ 8080                      β”‚
β”‚ APIKey      β”‚ ***************           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

JSON Format

Timestamped JSON output for production and centralized logging:

2026/01/31 10:30:15 {
  "DatabaseURL": "postgres://localhost:5432",
  "Port": 8080,
  "APIKey": "***************"
}

πŸ”’ Sensitive Data Protection

Automatically mask sensitive fields marked with secret:"true" tag in all output formats.

πŸ“¦ Default Values

Set fallback values using the envDefault tag when environment variables are not provided.

Usage

Environment Variables

GoConf supports loading configuration from environment variables with type-safe parsing.

  1. Define your configuration struct with environment variable mappings:
type AppConfig struct {
    // Basic string field
    AppName string `env:"APP_NAME" envDefault:"MyApp"`

    // Integer with validation
    Port int `env:"PORT" envDefault:"8080" validate:"gte=1024,lte=65535"`

    // Boolean flag
    Debug bool `env:"DEBUG" envDefault:"false"`

    // Required field with validation
    DatabaseURL string `env:"DATABASE_URL" validate:"required,uri"`

    // Sensitive data (will be masked in output)
    APISecret string `env:"API_SECRET" validate:"required" secret:"true"`
}
  1. Implement required interfaces:
var Config AppConfig

func (AppConfig) Register() error {
    return goconf.ParseEnv(&Config)
}

func (AppConfig) Validate() error {
    return goconf.StructValidator(Config)
}

func (AppConfig) Print() interface{} {
    return Config
}
  1. Load configuration:
func main() {
    if err := goconf.Load(new(AppConfig)); err != nil {
        log.Fatalf("Failed to load config: %v", err)
    }

    // Use your configuration
    log.Printf("Starting %s on port %d", Config.AppName, Config.Port)
}

YAML Configuration

GoConf supports loading configuration from YAML files, perfect for local development and structured configuration files.

  1. Define your configuration struct with YAML tag mappings:
type AppConfig struct {
    AppName  string `yaml:"app_name"`
    Port     int    `yaml:"port"`
    Debug    bool   `yaml:"debug"`

    Database struct {
        Host     string `yaml:"host"`
        Port     int    `yaml:"port"`
        Username string `yaml:"username"`
        Password string `yaml:"password" secret:"true"`
    } `yaml:"database"`
}
  1. Create a YAML configuration file (config.yaml):
app_name: MyApp
port: 8080
debug: true

database:
  host: localhost
  port: 5432
  username: dbuser
  password: secretpass
  1. Implement the Register interface to load from YAML:
var Config AppConfig

func (AppConfig) Register() error {
    return goconf.ParseYaml(&Config, "config.yaml")
}

func (AppConfig) Validate() error {
    return goconf.StructValidator(Config)
}

func (AppConfig) Print() interface{} {
    return Config
}
  1. Load configuration:
func main() {
    if err := goconf.Load(new(AppConfig)); err != nil {
        log.Fatalf("Failed to load config: %v", err)
    }

    log.Printf("Starting %s on port %d", Config.AppName, Config.Port)
}

Output:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CONFIG  β”‚   VALUE    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ AppName  β”‚ MyApp      β”‚
β”‚ Port     β”‚ 8080       β”‚
β”‚ Debug    β”‚ true       β”‚
β”‚ Database β”‚ {map data} β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Note: YAML configuration works seamlessly with validation and output formatting, just like environment variables.

Struct Tags

GoConf uses struct tags to configure field behavior:

Tag Description Example
env Environment variable name env:"PORT"
yaml YAML field name yaml:"port"
envDefault Default value if env var not set envDefault:"8080"
validate Validation rules (comma-separated) validate:"required,uri"
secret Mark field as sensitive (masks in output) secret:"true"

Example with multiple tags:

type Config struct {
    Port     int    `yaml:"port" validate:"gte=1024,lte=65535"`
    Password string `yaml:"password" secret:"true"`
}

Validation

GoConf uses go-playground/validator for validation. Common validation rules:

Rule Description Example
required Field must be set validate:"required"
uri Must be a valid URI validate:"uri"
email Must be a valid email validate:"email"
url Must be a valid URL validate:"url"
min=N Minimum length (string) or value (number) validate:"min=3"
max=N Maximum length (string) or value (number) validate:"max=100"
gte=N Greater than or equal to validate:"gte=0"
lte=N Less than or equal to validate:"lte=100"
oneof=A B C Value must be one of the options validate:"oneof=dev staging prod"

Multiple rules:

Port int `env:"PORT" validate:"required,gte=1024,lte=65535"`

Output Formats

Table Format (Default)

Best for local development and debugging:

func main() {
    // Table format is used by default
    if err := goconf.Load(new(Config)); err != nil {
        log.Fatal(err)
    }
}

JSON Format

Ideal for production environments, containerized deployments, and centralized logging systems:

func main() {
    // Switch to JSON format
    goconf.SetOutputFormat(goconf.OutputFormatJSON)

    if err := goconf.Load(new(Config)); err != nil {
        log.Fatal(err)
    }
}

Environment-based format selection:

func main() {
    // Use JSON in production, table in development
    if os.Getenv("ENV") == "production" {
        goconf.SetOutputFormat(goconf.OutputFormatJSON)
    }

    if err := goconf.Load(new(Config)); err != nil {
        log.Fatal(err)
    }
}

Interfaces

Configer

Must be implemented by configuration structs.

type Configer interface {
    Register() error
}

Validater (Optional)

Implement to enable validation.

type Validater interface {
    Validate() error
}

Printer (Optional)

Implement to enable configuration output.

type Printer interface {
    Print() interface{}
}

Constants

const (
    OutputFormatTable OutputFormat = "table" // Default: Unicode table
    OutputFormatJSON  OutputFormat = "json"  // JSON with timestamps
)

Best Practices

1. Use Validation Rules

Always validate critical configuration fields:

type Config struct {
    APIKey string `env:"API_KEY" validate:"required,min=32"`
    Port   int    `env:"PORT" validate:"required,gte=1024,lte=65535"`
}

2. Provide Sensible Defaults

Use envDefault for non-critical configuration:

type Config struct {
    Port     int    `env:"PORT" envDefault:"8080"`
    LogLevel string `env:"LOG_LEVEL" envDefault:"info"`
}

3. Mark Sensitive Data

Always mark secrets and passwords:

type Config struct {
    APIKey   string `env:"API_KEY" secret:"true"`
    Password string `env:"DB_PASSWORD" secret:"true"`
}

4. Use Environment-Specific Formats

if os.Getenv("ENVIRONMENT") == "production" {
    goconf.SetOutputFormat(goconf.OutputFormatJSON)
}

Organize configuration into logical groups:

type Config struct {
    Server   ServerConfig
    Database DBConfig
    Cache    CacheConfig
}

6. Document Environment Variables

Create a .env.example file:

# Application
APP_NAME=myapp
APP_VERSION=1.0.0

# Server
PORT=8080
HOST=0.0.0.0

# Database
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DB_USER=postgres
DB_PASSWORD=secret

7. Fail Fast on Configuration Errors

func main() {
    if err := goconf.Load(new(Config)); err != nil {
        log.Fatalf("Configuration error: %v", err)
    }
}

Contributing

We welcome contributions! Here’s how you can help:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Add amazing feature'
  4. Push to the branch: git push origin feature/amazing-feature
  5. Open a Pull Request

Development Setup

# Clone the repository
git clone https://github.com/wgarunap/goconf.git
cd goconf

# Install dependencies
go mod download

# Run tests
go test ./...

# Run tests with coverage
go test -v -cover ./...

Code Quality

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Support


Made with ❀️ for the Go community