Config: A Versatile Configuration Library for Go
Config
is a Go library designed to handle configuration from environment variables, files, and defaults in a flexible and intuitive way. It supports setting default values, loading configurations from various file types (such as .yaml
, .json
, etc.), and reading from environment variables, making it ideal for applications that require a versatile configuration management system.
Features
- Default values: Set default values that can be overridden by environment variables or file-based configurations.
- Environment variables: Automatically loads values from environment variables and overrides file-based or default configurations.
- File-based configurations: Supports loading configuration from files with different formats (
yaml
, json
, toml
, etc.). You can check Viper's documentation for a full list of supported formats.
- Global and internal variable precedence: Global environment variables can be reused across multiple structs, but internal struct variables will always take precedence over global ones.
Installation
go get github.com/PacoDw/config
Usage Example
Here is an example to showcase the flexibility of the config
library:
Sample .env
file
# global environment variables
name: "MyApp1.2"
app_environment: "local"
environment: "testing3"
server_port: 3000
# server environment variables
server:
SERVER_NAME: "MyApp"
host: "127.0.0.1"
environment: "dev"
# postgres environment variables
postgres:
user: "admin2"
host: "localhost"
DB_PORT: 5433
# server environment variables specific to serverconfig
serverconfig:
host: "localhost2"
server_port: 9000
environment: "dev3"
Go Code (main.go
)
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/PacoDw/config/config"
)
type AppConfig struct {
// Global environment variables that can be reused in other structs
Name string `env:"APP_NAME" validate:"required"`
Environment string `env:"ENVIRONMENT"`
Port int `env:"PORT" default:"8080"`
Server ServerConfig
Database DatabaseConfig `env:"postgres"`
}
type DatabaseConfig struct {
User string `env:"USER"`
Password string `env:"DB_PASSWORD" default:"my_default_password"`
Host string `env:"DB_HOST"`
Port int `env:"DB_PORT" default:"3052"`
}
type ServerConfig struct {
Name string `env:"SERVER_NAME" default:"my_default_server_name"`
Host string `env:"HOST" validate:"required"`
Port int `env:"SERVER_PORT"`
APIKey string `env:"api_key" default:"my_default_api_key"`
Environment string `env:"ENVIRONMENT" default:"user_env"`
}
func main() {
// Initialize config with defaults and load from .env.yaml
cfg := config.New()
var appConfig AppConfig
if err := cfg.Unmarshal(&appConfig); err != nil {
log.Fatalf("Error loading AppConfig: %v", err)
}
var serverConfig ServerConfig
if err := cfg.Unmarshal(&serverConfig); err != nil {
log.Fatalf("Error loading ServerConfig: %v", err)
}
// Output the app configuration in JSON
appConfigJSON, _ := json.MarshalIndent(appConfig, "", " ")
fmt.Printf("App Config (JSON): %s\n", appConfigJSON)
// Output the server configuration in JSON
serverConfigJSON, _ := json.MarshalIndent(serverConfig, "", " ")
fmt.Printf("Server Config (JSON): %s\n", serverConfigJSON)
}
Output
➜ go run main.go
App Config (JSON): {
"Name": "MyApp1.2",
"Environment": "testing3",
"Port": 8080,
"Server": {
"Name": "MyApp",
"Host": "127.0.0.1",
"Port": 3000,
"APIKey": "my_default_api_key",
"Environment": "dev"
},
"Database": {
"User": "admin2",
"Password": "my_default_password",
"Host": "",
"Port": 5433
}
}
Server Config (JSON): {
"Name": "my_default_server_name",
"Host": "localhost2",
"Port": 9000,
"APIKey": "my_default_api_key",
"Environment": "dev3"
}
Explanation of Behavior
-
Default values: If a value is not set in either the environment or the file, the default value specified in the struct tag is used. For example, the field Server.APIKey
has a default of "my_default_api_key"
since it is not present in the .env
file.
-
Global vs internal precedence: Global variables, like Environment
or Port
, will be reused across different structs (e.g., AppConfig
, ServerConfig
, etc.). However, if an internal struct like ServerConfig
defines a value for the same variable (e.g., ServerConfig.Environment
), this value will take precedence over the global one.
In this example:
- The global
environment
is set to "testing3"
, but the ServerConfig.Environment
is set to "dev"
, so "dev"
is used for the server.
Database.Password
defaults to "my_default_password"
because no value is provided for it in the .env
file.
Configuration Options
You can customize the path, file name, and file type by passing options when initializing the configuration:
cfg := config.New(
config.WithFilePath("/custom/path/"),
config.WithFileName("custom_config"),
config.WithFileType("json"),
)
This will load a configuration file located at /custom/path/custom_config.json
.
Validation
You can use the full suite of validation tags from the go-playground/validator
package. The example above uses the required
validation, but you can use many other tags like min
, max
, email
, etc. Check the official go-playground/validator documentation for more examples.
Config
leverages Viper under the hood, which supports a wide variety of configuration file formats including json
, yaml
, toml
, and more. You can refer to Viper's documentation for a full list of supported formats.
License
This project is licensed under the MIT License.