A flexible configuration management system for Go that supports reading from multiple providers and binding to user-defined types.
- Multiple Providers: Support for environment variables, JSON files, dotenv files, and more
- Flexible API: Easy-to-use interface for loading and binding configuration
- Extensible: Create custom providers by implementing the
Providerinterface - Hierarchical: Support for nested configuration using dot notation (e.g.,
database.host) - Merge Strategy: Later providers override earlier ones for flexible configuration layering
go get github.com/ahmedkamalio/gcfgpackage main
import (
"fmt"
"github.com/ahmedkamalio/gcfg"
)
type AppConfig struct {
Database struct {
Host string
Port int
}
Server struct {
Host string
Port int
}
}
func main() {
// Create config (environment provider is registered by default).
config := gcfg.New()
// Load configuration
if err := config.Load(); err != nil {
panic(err)
}
// Bind to your config struct
var appCfg AppConfig
if err := config.Bind(&appCfg); err != nil {
panic(err)
}
fmt.Printf("Server: %s:%d\n", appCfg.Server.Host, appCfg.Server.Port)
}package main
import (
"github.com/ahmedkamalio/gcfg"
)
func main() {
// Initialize config with JSON provider
config := gcfg.New(
gcfg.NewJSONProvider(
gcfg.WithJSONFilePath("config.json"),
),
)
// Load and bind as shown above
// ...
}Example config.json:
{
"database": {
"host": "localhost",
"port": 5432
},
"server": {
"host": "0.0.0.0",
"port": 8080
}
}Set environment variables:
export DATABASE_HOST=localhost
export DATABASE_PORT=5432
export SERVER_HOST=0.0.0.0
export SERVER_PORT=8080Then in your Go code:
config := gcfg.New(gcfg.NewEnvProvider())package main
import (
"github.com/ahmedkamalio/gcfg"
)
func main() {
// Initialize config with dotenv provider
config := gcfg.New(
gcfg.NewDotEnvProvider(), // defaults to ".env"
)
// Load and bind as shown above
// ...
}Example .env file:
DATABASE_HOST=localhost
DATABASE_PORT=5432
SERVER_HOST=0.0.0.0
SERVER_PORT=8080You can combine multiple providers, with later providers overriding earlier ones:
config := gcfg.New(
// Default values from JSON
gcfg.NewJSONProvider(gcfg.WithJSONFilePath("config.json")),
// Override with environment variables
gcfg.NewEnvProvider(),
// Override with .env file
gcfg.NewDotEnvProvider(),
)Creates a new configuration instance with the given providers. If no EnvProvider is provided, one will be added
automatically.
Sets a default value for the specified key in the configuration. Supports hierarchical paths like "database.host"
Sets default configuration values from a struct or map. Returns an error if the input is invalid or nil.
Loads configuration from all providers, merging values. Later providers override earlier ones.
Binds the loaded configuration to a Go struct using reflection.
Retrieves a configuration value by key (supports hierarchical paths like "database.host").
Returns all configuration values as a map.
type Provider interface {
Name() string
Load() (map[string]any, error)
}NewEnvProvider()- Loads from environment variablesNewJSONProvider(options ...JSONProviderOption)- Loads from JSON filesNewDotEnvProvider()- Loads from dotenv files
type CustomProvider struct{}
func (c *CustomProvider) Name() string {
return "custom"
}
func (c *CustomProvider) Load() (map[string]any, error) {
// Load configuration from your custom source
return map[string]any{
"my.setting": "value",
}, nil
}
// Use it
config := gcfg.New(&CustomProvider{})See the examples/ directory for complete examples:
basic/- Basic usagejson/- JSON configurationdotenv/- Dotenv filesjson_fs/- JSON with filesystem provider
All operations that can fail return errors that should be handled appropriately:
config := gcfg.New(gcfg.NewJSONProvider(gcfg.WithJSONFilePath("config.json")))
if err := config.Load(); err != nil {
log.Fatalf("Failed to load config: %v", err)
}
var appCfg AppConfig
if err := config.Bind(&appCfg); err != nil {
log.Fatalf("Failed to bind config: %v", err)
}Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License.