cfg is a lightweight yet powerful Go package for loading, managing, and saving application configuration files. It supports local and remote JSON configurations, environment variable interpolation, and provides a rich set of accessor functions for structured configuration data.
- β Load configuration from local files or HTTP(S) URLs
- β
Supports structured configuration for:
- Databases
- API Endpoints
- OAuth Providers
- Directories
- Notifications
- Caching
- Secrets
- Queues
- Flags
- FlagGroups and more
- π Environment variable interpolation using
${VAR_NAME}syntax - πΎ Save configuration back to disk (local files only)
- π Hot reload configuration without restarting the application
- π§ Access helpers for common lookups (e.g.,
GetDatabaseInfo,GetEndpointInfo) - π§° Type-safe flag retrieval with
GetFlag[T] - π§© Built-in defaults for common configuration values (e.g., IDs, cookie domain, secrets)
go get github.com/eaglebush/configReplace
github.com/eaglebush/configwith your actual module path.
package main
import (
"fmt"
"log"
"github.com/eaglebush/config"
)
func main() {
conf, err := cfg.Load("./config.json")
if err != nil {
log.Fatalf("failed to load config: %v", err)
}
fmt.Println("App Name:", *conf.ApplicationName)
// Access default database
db := conf.GetDatabaseInfo(*conf.DefaultDatabaseID)
if db != nil {
fmt.Println("DB ID:", db.ID)
fmt.Println("Conn String:", db.ConnectionString)
}
}You can use ${VAR_NAME} placeholders in your configuration file:
{
"Databases": [
{
"ID": "main",
"ConnectionString": "Server=${DB_HOST};User Id=${DB_USER};Password=${DB_PASS};"
}
]
}At runtime, cfg automatically interpolates these values from the environment.
export DB_HOST=localhost
export DB_USER=admin
export DB_PASS=secreterr := conf.Save()
if err != nil {
log.Println("Save failed:", err)
}
β οΈ Saving is only supported for local configuration files. Remote URLs are read-only.
Reload the configuration from the original source without restarting:
err := conf.Reload()
if err != nil {
log.Println("Reload failed:", err)
}The Configuration struct exposes various helper methods:
| Method | Description |
|---|---|
GetDatabaseInfo(id string) |
Get database by ID |
GetDatabaseInfoGroup(groupId string) |
Get databases by group |
GetEndpointInfo(id string) |
Get API endpoint by ID (uses default if empty) |
GetEndpointInfoGroup(groupId string) |
Get endpoints by group |
GetDirectory(groupId string) |
Get directory by group ID |
GetDirectoryItem(groupId, key string) |
Get specific directory item |
GetDomainInfo(name string) |
Get domain info |
GetFlagGroupFlags(groupId string) |
Gets flags from defined group |
GetNotificationInfo(id string) |
Get notification by ID (uses default if empty) |
GetSourceInfo(id string) |
Get source by ID |
GetOAuthInfo(id string) |
Get OAuth provider by ID |
GetSecretInfo(id string) |
Get secret by ID |
GetSecretInfoGroup(groupId string) |
Get secrets by group ID |
The configuration can include a list of Flags for miscellaneous values. You can retrieve them safely with type inference:
value := cfg.GetFlag[string](conf.Flags, "SOME_KEY")
timeout := cfg.GetFlag[int](conf.Flags, "TIMEOUT")If the flag is missing or can't be converted, a zero value is returned.
Additionally, Configuration.Flag(key) provides a convenient way to find a flag by key, ignoring underscores and dashes.
The following fields support ${ENV} placeholders:
DatabaseInfo.ConnectionStringEndpointInfo.Address,APIKey,TokenOAuthProviderInfo.IconUrl,ProviderHost,ProviderWebUri,ProviderApiUriNotificationInfo.APIHost,Login,Password,SenderAddress,ReplyToCacheInfo.Address,Password
Values are interpolated once on load, and then restored to original values before saving.
{
"APIEndpoints": [
{
"ID": "DEFAULT",
"Address": "https://${API_HOST}/v1",
"APIKey": "${API_KEY}"
}
]
}Configuration is the central struct:
type Configuration struct {
ApplicationID *string
ApplicationName *string
Databases *[]DatabaseInfo
APIEndpoints *[]EndpointInfo
Notifications *[]NotificationInfo
OAuths *[]OAuthProviderInfo
Directories *[]DirectoryInfo
Flags *[]Flag
FlagGroups *[]FlagGroup
Cache *CacheInfo
Secrets *[]SecretInfo
Sources *[]SourceInfo
Queue *QueueInfo
CookieDomain *string
JWTSecret *string
Secure *bool
ReadTimeout *int
WriteTimeout *int
}DatabaseInfoβ defines connection details, pooling, and SQL formatting options.EndpointInfoβ represents API endpoints with optionalAPIKey,Token, and attached secrets.OAuthProviderInfoβ stores OAuth2 client and provider details.NotificationInfoβ holds notification service connection settings.CacheInfoβ caching backend information.QueueInfoβ queue/streaming configuration.SecretInfoβ grouped secrets for secure data.DirectoryInfoβ configuration for grouped flags.
{
"ApplicationName": "MyApp",
"Databases": [
{
"ID": "main",
"DriverName": "sqlserver",
"ConnectionString": "Server=${DB_HOST};User Id=${DB_USER};Password=${DB_PASS};"
}
],
"APIEndpoints": [
{
"ID": "DEFAULT",
"Name": "Main API",
"Address": "https://api.example.com"
}
],
"Flags": [
{ "Key": "TIMEOUT", "Value": "30" }
]
}When a configuration is loaded, default values are applied where missing:
| Field | Default Value |
|---|---|
CookieDomain |
localhost |
JWTSecret |
defaultsecretkey |
DatabaseInfo.StorageType |
SERVER |
DatabaseInfo.InterpolateTables |
true |
DatabaseInfo.StringEnclosingChar |
' |
DatabaseInfo.StringEscapeChar |
\\ |
DatabaseInfo.ReservedWordEscapeChar |
" |
| Error | Meaning |
|---|---|
ErrNoDataFromSource |
No data was read from the configuration source |
ErrSaveNotLocalFile |
Tried to save a remote (non-local) configuration |
Replaces ${ENV_VAR} tokens in text with values from os.Getenv().
Generic helper that finds structs in a slice by a string ID (case-insensitive).
The Configuration type is not thread-safe. Use synchronization (like sync.RWMutex) when accessing or modifying configuration concurrently.
- Use temporary files for
Load()/Save()tests. - Use
t.Setenv()to mock environment variables. - Confirm that saved JSON preserves uninterpolated values.
- Validate that in-memory state remains interpolated post-save.
MIT β feel free to use, modify, and contribute.
Pull requests and issues are welcome. Please run go fmt ./... before submitting any changes.
Developed and maintained by Elizalde Baguinon.