README
¶
Config Auto-Discovery Examples
This directory demonstrates Forge's automatic configuration file discovery and loading, similar to how Next.js handles environment files.
Features
- Automatic Discovery: Searches for
config.yamlandconfig.local.yamlautomatically - Local Overrides:
config.local.yamloverridesconfig.yaml(add to.gitignore) - Monorepo Support: App-scoped configs with
apps.{app-name}sections - Hierarchical Search: Searches current directory and parent directories
- Next.js-like Behavior: Familiar pattern for web developers
Directory Structure
config-autodiscovery/
├── single-app/ # Single application example
│ ├── config.yaml # Base config (committed)
│ ├── config.local.yaml # Local overrides (gitignored)
│ └── main.go
│
└── monorepo/ # Monorepo with multiple apps
├── config.yaml # Root config for all apps
├── config.local.yaml # Local overrides for all apps
└── apps/
├── api-service/
│ └── main.go
├── admin-dashboard/
│ └── main.go
└── worker-service/
└── main.go
Single-App Pattern
Directory Layout
my-app/
├── config.yaml # Base configuration
├── config.local.yaml # Local overrides (in .gitignore)
└── main.go
Usage
app := forge.NewApp(forge.AppConfig{
Name: "my-app",
Version: "1.0.0",
// Config auto-discovery is enabled by default
// No need to manually load config files!
})
// Access configuration
cfg := app.Config()
dbHost := cfg.GetString("database.host")
How It Works
- Forge searches for
config.yamlorconfig.yml - Loads base configuration
- Searches for
config.local.yamlorconfig.local.yml - Merges local config over base (local takes precedence)
Example Config Files
config.yaml (committed to git):
database:
host: db.production.com
port: 5432
cache:
driver: redis
url: redis://cache.production.com:6379
config.local.yaml (in .gitignore):
database:
host: localhost # Override for local dev
cache:
driver: inmemory # Override for local dev
Monorepo Pattern
Directory Layout
monorepo/
├── config.yaml # Root config with all apps
├── config.local.yaml # Local overrides
└── apps/
├── api-service/
│ └── main.go
├── admin-dashboard/
│ └── main.go
└── worker-service/
└── main.go
Usage in Each App
// In apps/api-service/main.go
app := forge.NewApp(forge.AppConfig{
Name: "api-service", // Matches apps.api-service in config
Version: "1.0.0",
// App-scoped config extraction is enabled by default
})
How It Works
- Forge searches up the directory tree for
config.yaml - Finds root
config.yamland loads it - Extracts
apps.api-servicesection - Merges global settings with app-specific settings
- Applies local overrides from
config.local.yaml
Config Merge Order
Global Config (database, cache, logging)
↓
App-Scoped Config (apps.api-service)
↓
Local Overrides (config.local.yaml)
↓
Final Configuration
Example Monorepo Config
config.yaml:
# Global settings for all apps
database:
driver: postgres
host: db.company.com
port: 5432
cache:
driver: redis
# App-specific configurations
apps:
api-service:
app:
port: 8080
database:
name: api_service_db
api:
rate_limit: 1000
admin-dashboard:
app:
port: 8081
database:
name: admin_db
admin:
session_timeout: 30m
config.local.yaml:
# Override for local development
database:
host: localhost
apps:
api-service:
database:
name: api_service_dev
cache:
driver: inmemory
admin-dashboard:
database:
name: admin_dev
Configuration Options
You can customize auto-discovery behavior:
app := forge.NewApp(forge.AppConfig{
Name: "my-app",
Version: "1.0.0",
// Customize auto-discovery
EnableConfigAutoDiscovery: true, // Default: true
EnableAppScopedConfig: true, // Default: true
ConfigBaseNames: []string{"config.yaml", "config.yml"},
ConfigLocalNames: []string{"config.local.yaml", "config.local.yml"},
ConfigSearchPaths: []string{"/path/to/configs"},
})
Running the Examples
Single-App Example
cd examples/config-autodiscovery/single-app
go run main.go
# Visit http://localhost:8080/config
Monorepo Example
Run API Service:
cd examples/config-autodiscovery/monorepo/apps/api-service
go run main.go
# Visit http://localhost:8080/config
Run Admin Dashboard:
cd examples/config-autodiscovery/monorepo/apps/admin-dashboard
go run main.go
# Visit http://localhost:8081/config
Run Worker Service:
cd examples/config-autodiscovery/monorepo/apps/worker-service
go run main.go
# Visit http://localhost:8082/config
Best Practices
1. Use .gitignore
Always add local config files to .gitignore:
config.local.yaml
config.local.yml
*.local.yaml
*.local.yml
2. Document Config Structure
Provide a config.example.yaml or document all config keys:
# config.example.yaml - Copy to config.local.yaml for local development
database:
host: localhost
port: 5432
name: myapp_dev
3. Use Environment Variables for Secrets
Never commit secrets. Use environment variable expansion:
database:
password: ${DB_PASSWORD} # Loaded from environment
api_key: ${API_KEY} # Loaded from environment
4. Monorepo Organization
# Shared global settings
database: &database-defaults
driver: postgres
port: 5432
# App-specific configs
apps:
api-service:
database:
<<: *database-defaults
name: api_db
5. Config Validation
Always validate required config:
cfg := app.Config()
// Validate required settings
if !cfg.IsSet("database.host") {
log.Fatal("database.host is required")
}
Troubleshooting
Config Not Found
If config files aren't being discovered:
// Enable debug logging to see search paths
app := forge.NewApp(forge.AppConfig{
Name: "my-app",
Logger: forge.NewBeautifulLogger("my-app"),
})
// Check search info
fmt.Println(config.GetConfigSearchInfo("my-app"))
Wrong Config Loaded
Verify the merge order and precedence:
- Base config (
config.yaml) is loaded first - Local config (
config.local.yaml) overrides base - App-scoped config (
apps.{name}) overrides global - Local app-scoped overrides everything
App-Scoped Not Working
Ensure:
- App name matches the key in
apps.{name} EnableAppScopedConfigistrue(default)- You're using the correct config structure:
apps: your-app-name: # Must match AppConfig.Name # your config here
Comparison with Next.js
| Feature | Next.js | Forge |
|---|---|---|
| Base file | .env |
config.yaml |
| Local overrides | .env.local |
config.local.yaml |
| Environment-specific | .env.production |
config.{env}.yaml |
| Monorepo support | Built-in | Built-in with apps.{name} |
| Auto-discovery | ✅ | ✅ |
| Hierarchical search | ✅ | ✅ |
Additional Resources
Directories
¶
| Path | Synopsis |
|---|---|
|
monorepo
|
|
|
apps/admin-dashboard
command
|
|
|
apps/api-service
command
|
|
|
apps/worker-service
command
|
|
Click to show internal directories.
Click to hide internal directories.