Conform
The Pydantic for Go
Type-safe configuration loading, validation, and management in one elegant package.
Features * Quick Start * Documentation * Examples
Why Conform?
Stop juggling multiple libraries. Conform unifies configuration loading, type conversion, and validation into a single, declarative interface.
Key Benefits
- Zero Boilerplate - Declare everything in struct tags, no manual parsing or validation code
- Type Safety - Full generics support ensures compile-time type checking
- Production Ready - Built-in support for environment-specific configs, hot reload, and variable substitution
- Developer Experience - Beautiful, actionable error messages that tell you exactly what's wrong
- Flexible - Support for multiple sources, custom validators, and converters
- Lightweight - Minimal dependencies, fast performance
Before Conform
viper.SetConfigFile("config.yaml")
viper.ReadInConfig()
// Unmarshal
var cfg Config
viper.Unmarshal(&cfg)
// Validate
validate := validator.New()
if err := validate.Struct(cfg); err != nil {
// Parse errors...
}
// Type conversion? Manual!
port, _ := strconv.Atoi(viper.GetString("port"))
timeout, _ := time.ParseDuration(viper.GetString("timeout"))
With Conform
Port int `conform:"env=PORT,default=8080,validate=gte:1024"`
Timeout time.Duration `conform:"env=TIMEOUT,default=30s"`
Database string `conform:"env=DB_URL,required,validate=url"`
}
cfg, err := conform.LoadGeneric[Config](conform.FromEnv())
// Done! Type-safe, validated, ready to use.
One struct tag. One function call. Zero boilerplate.
Perfect For
- Microservices - Type-safe configuration across services
- Cloud-Native Apps - Environment-specific configs for Kubernetes, Docker
- CLI Tools - Easy configuration management
- APIs & Web Services - Fast, validated config loading
- Testing - Mock-friendly configuration loading
Features
Core Features
| Feature | Description |
|---|---|
| Declarative Configuration | Everything in struct tags, zero boilerplate |
| Type-Safe Generics | Full type safety with Go 1.21+ generics |
| Multi-Source Support | Environment variables, files (YAML/JSON/TOML), custom sources |
| Built-in Validation | 20+ validators out of the box |
| Smart Type Coercion | Automatic conversion for complex types |
| Nested Structs | Full support with automatic prefix handling |
| Hot Reload | Watch for changes and reload automatically |
| Beautiful Errors | Detailed error messages with suggestions |
| Environment-Specific | Load different configs for dev/staging/prod |
| Variable Substitution | ${VAR_NAME:-default} syntax support |
What Makes Conform Different?
| Feature | Conform | Viper | envconfig | koanf |
|---|---|---|---|---|
| Type Safety | Generics | |||
| Validation | Built-in | Requires validator | ||
| Error Messages | Beautiful | |||
| Hot Reload | Built-in | WatchConfig | ||
| Environment-Specific | Built-in | |||
| Variable Substitution | Built-in | |||
| Declarative | 100% | |||
| Zero Boilerplate |
Note:
- Viper requires separate validation library (e.g.,
go-playground/validator) - envconfig is minimal and focused only on environment variables
- koanf is a modern alternative but lacks generics and built-in validation
Installation
Go Module
Import
Requirements
- Go 1.21 or higher
- No external dependencies required (except for file format support: YAML, TOML)
Quick Start
Basic Example
Define your configuration struct with conform tags:
import (
"fmt"
"os"
"github.com/alicanli1995/conform"
)
type Config struct {
Port int `conform:"env=APP_PORT,default=8080,validate=gte:1024"`
Host string `conform:"env=APP_HOST,default=localhost,validate=hostname"`
Database string `conform:"env=DATABASE_URL,required,validate=url"`
}
func main() {
os.Setenv("APP_PORT", "3000")
os.Setenv("DATABASE_URL", "postgres://localhost/mydb")
cfg, err := conform.LoadGeneric[Config](conform.FromEnv())
if err != nil {
panic(err) // Beautiful error messages!
}
fmt.Printf("Server: %s:%d\n", cfg.Host, cfg.Port)
}
That's it! Your configuration is loaded, validated, and ready to use.
What Just Happened?
- Loaded from environment variables
- Converted types automatically (
string-int) - Validated against rules (
gte:1024,hostname,url) - Applied defaults where needed
- Returned type-safe config struct
Try It Yourself
cd examples/basic && go run main.go
Documentation
Multi-Source Support
Load from multiple sources with automatic priority (first source wins):
conform.FromEnv(), // Highest priority
conform.FromFile("secrets.json"), // Second priority
conform.FromFile("config.yaml"), // Third priority
conform.WithSource(&CustomSource{}), // Custom source
)
// Priority: env > custom sources > file sources > defaults
Environment-Specific Configuration
Perfect for dev/staging/production environments:
Database struct {
Host string `conform:"file=database.host,default=localhost"`
Port int `conform:"file=database.port,default=5432"`
}
}
// Development
devCfg, _ := conform.LoadGeneric[Config](
conform.WithEnvironment("development"),
conform.FromFile("config.${ENV}.yaml"), // Loads config.development.yaml
)
// Production
prodCfg, _ := conform.LoadGeneric[Config](
conform.WithEnvironment("production"),
conform.FromFile("config.${ENV}.yaml"), // Loads config.production.yaml
)
Variable Substitution
Use ${VAR_NAME:-default} syntax in config values:
DatabaseURL string `conform:"env=DB_URL,default=postgres://${DB_USER:-postgres}:${DB_PASSWORD}@${DB_HOST:-localhost}:${DB_PORT:-5432}/${DB_NAME:-mydb}"`
APIURL string `conform:"env=API_URL,default=https://api.${ENV:-dev}.example.com"`
}
Smart Type Coercion
Automatic conversion for complex types:
// String "true" - bool true
Debug bool `conform:"env=DEBUG"`
// String "30s" - time.Duration
Timeout time.Duration `conform:"env=TIMEOUT"`
// String "1,2,3" - []int{1,2,3}
IDs []int `conform:"env=IDS,separator=,"`
// String "1=one,2=two" - map[int]string{1:"one", 2:"two"}
Mapping map[int]string `conform:"env=MAPPING"`
// String "2024-01-01" - time.Time
StartDate time.Time `conform:"env=START,format=2006-01-02"`
}
Beautiful Error Messages
Get detailed, actionable error messages:
if err != nil {
fmt.Println(err)
// Output:
// Configuration validation failed:
//
// 1. Port (APP_PORT): value 80 is too small
// Got: 80
// Location: env var APP_PORT
// Suggestion: Use a value >= 1024 (e.g. 8080)
//
// 2. Database.URL (DB_URL): invalid URL format
// Got: "not-a-url"
// Expected: valid URL with scheme
// Suggestion: Format should be: https://example.com
}
Hot Reload
Watch for configuration changes automatically:
log.Printf("Config reloaded: %+v", newCfg)
// Update your application state here
}, conform.FromEnv(), conform.FromFile("config.yaml"))
// Thread-safe access
cfg := watcher.Get()
// Stop watching
defer watcher.Stop()
Custom Validators
Register your own validation rules:
str := val.(string)
if len(str) < 12 {
return fmt.Errorf("password must be at least 12 characters")
}
if !hasSpecialChar(str) {
return fmt.Errorf("password must contain special character")
}
return nil
})
type Config struct {
Password string `conform:"env=PASSWORD,validate=strong_password"`
}
Custom Converters
Convert to custom types:
conform.RegisterConverter(
reflect.TypeOf(CustomType("")),
func(s string) (interface{}, error) {
return CustomType("custom_" + s), nil
},
)
type Config struct {
Custom CustomType `conform:"env=CUSTOM"`
}
Nested Configuration
Full support for nested structs with automatic prefix handling:
Host string `conform:"env=HOST,default=localhost"`
Port int `conform:"env=PORT,default=5432"`
}
type AppConfig struct {
Name string `conform:"env=APP_NAME,default=MyApp"`
Database DatabaseConfig `conform:"prefix=DB_"`
}
// Environment variables:
// DB_HOST=db.example.com
// DB_PORT=5432
File Configuration
Support for YAML, JSON, and TOML:
Server struct {
Host string `conform:"file=server.host,default=localhost"`
Port int `conform:"file=server.port,default=8080"`
}
}
// YAML
cfg, _ := conform.LoadGeneric[Config](conform.FromFile("config.yaml"))
// TOML
cfg, _ := conform.LoadGeneric[Config](conform.FromFile("config.toml"))
// JSON
cfg, _ := conform.LoadGeneric[Config](conform.FromFile("config.json"))
Tag Reference
Source Tags
| Tag | Description | Example |
|---|---|---|
env=VAR_NAME |
Load from environment variable | env=APP_PORT |
file=key.path |
Load from config file (dot notation) | file=database.host |
default=value |
Default value if not found | default=8080 |
required |
Field is required (error if missing) | required |
prefix=PREFIX_ |
Prefix for nested structs | prefix=DB_ |
Type Conversion Tags
| Tag | Description | Example |
|---|---|---|
format=layout |
Format for time.Time | format=2006-01-02 |
separator=, |
Separator for slices | separator=| |
Validation Tags
| Tag | Description | Example |
|---|---|---|
validate=rule:param |
Validation rules | validate=gte:1024,lte:65535 |
Built-in Validators
Numeric Validators
min:value- Minimum value/lengthmax:value- Maximum value/lengthgte:value- Greater than or equallte:value- Less than or equaleq:value- Equal tone:value- Not equal to
String Validators
email- Valid email addressurl- Valid URL (useurl:httpsfor HTTPS only)ip- Valid IP address (IPv4 or IPv6)hostname- Valid hostnameport- Valid port number (1-65535)alphanum- Only letters and digitsalpha- Only lettersnumeric- Only digitsregex:pattern- Match regex patternoneof:val1:val2- One of the specified valueslen:length- Exact length
Password Validators
has_upper- Contains uppercase letterhas_lower- Contains lowercase letterhas_digit- Contains digithas_special- Contains special character
General
required- Field is required
CLI Tool
Note: CLI tool is currently in development. For now, use the programmatic API for validation.
Validate configuration files programmatically:
conform.FromFile("config.yaml"),
conform.FromEnv(),
)
if err != nil {
fmt.Println(err) // Beautiful error messages
}
Examples
Comprehensive examples available in the examples directory:
| Example | Description | Link |
|---|---|---|
| Basic Usage | Getting started with Conform | View |
| Generic API | Type-safe loading with generics | View |
| File Configuration | YAML, JSON, TOML examples | View |
| Environment-Specific | Dev/staging/prod configs | View |
| Advanced Features | Complex scenarios | View |
| Custom Extensions | Custom converters & validators | View |
| Hot Reload | Dynamic configuration | View |
| Error Handling | Beautiful error messages | View |
| Real-World | Production-ready example | View |
Run All Examples
Roadmap
Upcoming Features
- Secret Management - HashiCorp Vault, AWS Secrets Manager, Azure Key Vault integration
- Remote Configuration - etcd integration for distributed config management
- JSON Schema Validation - External schema validation support
- Config Documentation - Auto-generate config docs from struct definitions
- Config Diff/Compare - Track and compare configuration changes
- Metrics & Observability - Prometheus metrics for config usage monitoring
License
This project is licensed under the MIT License - see the LICENSE file for details.
Made with for the Go community
Star us on GitHub * pkg.go.dev * Documentation * Issues * Report Bug