Load configuration files from multiple directories and merge them together. Supports YAML, JSON, and other formats.
- Load configs from multiple directories
- Merge YAML, JSON, and other file formats
- Directory precedence (first directory wins)
- Static (cached) or dynamic (reloaded) config files
- Returns
HashWithIndifferentAccessfor easy key access
Add to your Gemfile:
gem 'config_files'Or install it:
gem install config_filesrequire 'config_files'
class MyApp
include ConfigFiles
# Search these directories in order (first wins)
config_directories etc: [
'config/production',
'config/staging',
'config/defaults'
]
# Load these config files
static_config_files :database, :app_settings
dynamic_config_files :feature_flags
end
# Use the configs
MyApp.database[:host] # => "prod-db.example.com"
MyApp.app_settings[:debug] # => false
MyApp.feature_flags[:new_ui] # => true (reloaded each time)The gem searches for config files in each directory you specify. If you have:
config/production/database.yml
config/staging/database.yml
config/defaults/database.yml
And you configure directories as ['config/production', 'config/staging', 'config/defaults'], then:
- It loads all three files
- Merges them together
- Values from
productionoverridestaginganddefaults - Values from
stagingoverridedefaults - Returns the merged result
You can mix YAML and JSON files:
config/
├── app.yml # YAML format
├── app.json # JSON format
└── app.conf # Other formats
All files with the same base name get merged together. Files are processed alphabetically, so app.json loads before app.yml.
class AppConfig
include ConfigFiles
config_directories etc: ['config']
# Static: loaded once and cached
static_config_files :database
# Dynamic: reloaded from disk each time
dynamic_config_files :feature_flags
end
AppConfig.database # Fast (cached)
AppConfig.feature_flags # Slower (reads from disk)Use static for configs that don't change. Use dynamic for configs that might change while your app is running.
Earlier directories in the list win:
config_directories etc: [
'config/production', # Highest priority
'config/staging', # Medium priority
'config/defaults' # Lowest priority
]So if production/app.yml has debug: false and defaults/app.yml has debug: true, the result will have debug: false.
Configs are deep-merged. Given these files:
# config/defaults/app.yml
database:
host: localhost
port: 5432
pool_size: 5
app:
debug: true
name: MyApp# config/production/app.yml
database:
host: prod-db.example.com
pool_size: 20
app:
debug: falseThe result is:
{
database: {
host: "prod-db.example.com", # from production
port: 5432, # from defaults
pool_size: 20 # from production
},
app: {
debug: false, # from production
name: "MyApp" # from defaults
}
}You can use different directory sets:
class AppConfig
include ConfigFiles
config_directories(
etc: ['config/app', '/etc/myapp'],
secrets: ['secrets/production', 'secrets/shared']
)
static_config_files :database # searches in 'etc' directories
end
# Access the directory paths
AppConfig.etc_dir # => ["/full/path/to/config/app", "/etc/myapp"]
AppConfig.secrets_dir # => ["/full/path/to/secrets/production", ...]Missing files and directories are ignored:
class AppConfig
include ConfigFiles
config_directories etc: [
'config/nonexistent', # ignored
'config/existing' # used
]
static_config_files :missing_file
end
AppConfig.missing_file # => {} (empty hash)Run the tests:
bundle exec rake testTest with multiple Ruby versions:
./scripts/test_multiple_rubies.shThe gem is tested on Ruby 2.7+ with ActiveSupport 6.1+. See TESTING.md for details.
Define search directories:
config_directories etc: ['dir1', 'dir2']Load files once and cache them:
static_config_files :database, :app_settingsReload files on each access:
dynamic_config_files :feature_flags- Fork it
- Create your feature branch (
git checkout -b my-feature) - Make your changes
- Run the tests (
bundle exec rake test) - Commit your changes (
git commit -am 'Add feature') - Push to the branch (
git push origin my-feature) - Create a Pull Request
MIT License. See LICENCE.txt for details.
See CHANGELOG.md for version history and changes.