A lightweight, flexible Go library for loading and validating environment-based configuration with beautiful output formatting.
GoConf simplifies configuration management in Go applications by providing:
- Type-safe configuration - Parse environment variables and YAML files directly into Go structs
- Multiple sources - Load configuration from environment variables or YAML files
- Validation - Built-in validation using struct tags
- Default values - Support for default values when environment variables are not set
- Sensitive data masking - Automatically mask sensitive fields in output
- Multiple output formats - Table format for development, JSON format for production
- Zero configuration - Works out of the box with sensible defaults
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.
go get github.com/wgarunap/goconfpackage 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!")
}- Automatically parse environment variables into typed struct fields
- Support for common Go types:
string,int,bool,float64, etc. - Custom type support through struct tag configuration
- Powered by go-playground/validator
- Extensive validation rules:
required,uri,email,min,max,gte,lte, etc. - Custom validation rules support
Beautiful Unicode table output for development environments:
┌─────────────┬───────────────────────────┐
│ CONFIG │ VALUE │
├─────────────┼───────────────────────────┤
│ DatabaseURL │ postgres://localhost:5432 │
│ Port │ 8080 │
│ APIKey │ *************** │
└─────────────┴───────────────────────────┘
Timestamped JSON output for production and centralized logging:
2026/01/31 10:30:15 {
"DatabaseURL": "postgres://localhost:5432",
"Port": 8080,
"APIKey": "***************"
}
Automatically mask sensitive fields marked with secret:"true" tag in all output formats.
Set fallback values using the envDefault tag when environment variables are not provided.
GoConf supports loading configuration from environment variables with type-safe parsing.
- 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"`
}- 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
}- 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)
}GoConf supports loading configuration from YAML files, perfect for local development and structured configuration files.
- 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"`
}- Create a YAML configuration file (
config.yaml):
app_name: MyApp
port: 8080
debug: true
database:
host: localhost
port: 5432
username: dbuser
password: secretpass- 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
}- 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.
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"`
}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"`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)
}
}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)
}
}Must be implemented by configuration structs.
type Configer interface {
Register() error
}Implement to enable validation.
type Validater interface {
Validate() error
}Implement to enable configuration output.
type Printer interface {
Print() interface{}
}const (
OutputFormatTable OutputFormat = "table" // Default: Unicode table
OutputFormatJSON OutputFormat = "json" // JSON with timestamps
)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"`
}Use envDefault for non-critical configuration:
type Config struct {
Port int `env:"PORT" envDefault:"8080"`
LogLevel string `env:"LOG_LEVEL" envDefault:"info"`
}Always mark secrets and passwords:
type Config struct {
APIKey string `env:"API_KEY" secret:"true"`
Password string `env:"DB_PASSWORD" secret:"true"`
}if os.Getenv("ENVIRONMENT") == "production" {
goconf.SetOutputFormat(goconf.OutputFormatJSON)
}Organize configuration into logical groups:
type Config struct {
Server ServerConfig
Database DBConfig
Cache CacheConfig
}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=secretfunc main() {
if err := goconf.Load(new(Config)); err != nil {
log.Fatalf("Configuration error: %v", err)
}
}We welcome contributions! Here's how you can help:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
# 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 ./...- Write clear, idiomatic Go code
- Add tests for new features
- Ensure all tests pass
- Update documentation
- Follow existing code style
This project is licensed under the MIT License - see the LICENSE file for details.
- caarlos0/env - Environment variable parsing
- go-playground/validator - Struct validation
- olekukonko/tablewriter - ASCII table formatting
- 📫 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
- 📖 Documentation: pkg.go.dev
Made with ❤️ for the Go community