Open-source project
rubyconfig/config avatar
rubyconfig/config

rubyconfig/config merges six YAML files into one global Settings object, and the order decides every value

Easiest way to add multi-environment yaml settings to Rails, Sinatra, Padrino and other Ruby projects.

2,171 stars231 forksRubyNOASSERTION

At a glance

What is it?
The config gem for Rails, Sinatra, Padrino and plain Ruby builds a global Settings object from layered YAML files. This review covers the merge order, the local-file rules, the extra source types and the Ruby and Rails versions each major release covers.
Who is it for?
Pick this gem when a Ruby app needs per-environment YAML with ERB and a per-developer override file, and the team is happy with a global Settings constant. Skip it if you need settings that cannot be reloaded from disk or a source other than files, hashes and objects with a load method.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 102 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • rubyconfig/config2,171 ★ · +2
Star history
Repository2026-10-082026-11-07
rubyconfig/config2.2k2.2k

2 Stars in the last 30 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Files lower in the list override files higher in it, and the local files come last

Once the gem is installed, a global Settings object is compiled from up to six files. Files lower in this list override the ones above them:

code
config/settings.yml
config/settings/#{environment}.yml
config/environments/#{environment}.yml

config/settings.local.yml
config/settings/#{environment}.local.yml
config/environments/#{environment}.local.yml

The split into two groups is the whole design. The first three files are committed and describe the application. The second three are the developer's own and win every conflict. A value that is wrong on one laptop can be corrected without touching the shared file, and the local group is automatically gitignored, so the correction does not leak into a commit.

The consequence is that a surprising value always has a definite source. When Settings.my_section.some_entry returns something unexpected, the answer is in one of six paths, and the bottom-most file that defines the key is the one that won. Environment specific entries take precedence over the common ones, and that is the extent of the precedence model.

settings.local.yml is deliberately skipped when the test suite runs

One local file behaves differently from its siblings. settings.local.yml is not loaded in tests, so a developer's private tweaks cannot make a spec pass on one machine and fail on another. Environment specific local files such as settings/test.local.yml are still loaded, which leaves a place for test-only credentials.

This catches people who assume all three local files are equal. If you put a value in settings.local.yml and expect your test run to see it, it will not. Move it to settings/test.local.yml. The reverse also holds: a test that depends on a value from settings.local.yml is reading a value that the test environment never loads.

The gem draws the line where flaky tests usually come from, but it also means the test environment is configured by a narrower set of files than development. Anyone debugging a difference between a local run and CI should start by listing which of the six files exist in each place.

Rails gets a generator, Sinatra needs a root, and everything else calls load_and_set_settings

Installation differs by framework, and only Rails is automated. After adding gem 'config' to the Gemfile and running bundle install, Rails apps run:

code
rails g config:install

That writes config/initializers/config.rb plus config/settings.yml, config/settings.local.yml, config/settings/development.yml, config/settings/production.yml and config/settings/test.yml. By default the config environment matches Rails.env, and setting config.environment changes that.

Padrino needs one line in app.rb after the gem is bundled:

ruby
register Config

Sinatra needs the same registration plus a root so the gem can find the files:

ruby
set :root, File.dirname(__FILE__)
register Config

For any other Ruby project the initialization is manual and goes inside your configure block:

ruby
Config.load_and_set_settings(Config.setting_files("/path/to/config_root", "your_project_environment"))

You can also skip the directory convention and hand it explicit paths with Config.load_and_set_settings("/path/to/yaml1", "/path/to/yaml2", ...). The root exists so the gem can find the config files, so a Sinatra app without it has nowhere to look.

extra_sources takes a path, a hash, or any object that responds to load

The default file list covers most apps, but Config.setup exposes an extra_sources option for everything else. Each entry in the array can be one of three things:

ruby
Config.setup do |config|
  config.extra_sources = [
    'path/to/extra_source.yml',          # String: loads extra_source.yml
    { api_key: ENV['API_KEY'] },         # Hash: direct hash source
    MyCustomSource.new,                  # Object: custom source object that responds to `load`
  ]
end

The hash form is how an environment variable becomes a setting without writing a YAML file for it. The object form is the escape hatch: anything that responds to load can feed values in, so a custom class can supply values from wherever you choose. The class is yours to write.

Extra sources also overwrite the same entries from the main file. That matters when you combine them with the six-file order: a hash source holding api_key beats a value of api_key in settings.yml, so an environment variable can silently replace a committed default. Anyone reviewing a pull request that adds a source should check which committed keys it shadows.

add_source! appends, prepend_source! sets defaults, and neither takes effect until reload!

Sources can also change while the process runs. Settings.add_source! puts a YAML file at the end of the list, so its values overwrite anything loaded before it:

ruby
Settings.add_source!("/path/to/source.yml")
Settings.reload!

Settings.prepend_source! does the opposite. The file is loaded first and every other file can overwrite it, which makes it the right tool for defaults:

ruby
Settings.prepend_source!("/path/to/source.yml")
Settings.reload!

Both calls only register the file. The Settings.reload! after each is what rebuilds the object, and leaving it out means the new file is on the list but nothing has read it. Settings.reload! on its own re-reads the existing files at any time.

The documentation also shows a per-developer pattern for Rails: a gitignored local.yml registered from config/initializers/add_local_config.rb with Settings.add_source!("#{Rails.root}/config/settings/local.yml") followed by Settings.reload!. The same documentation then points out that the default settings.local.yml already does this job, so the extra initializer is only worth writing when the file needs a different name or location.

Testing production settings means swapping the file list with reload_from_files

Because Settings is a global, a test that wants production values cannot just set an environment variable and expect the object to follow. The gem offers Settings.reload_from_files, which replaces the file list outright and rebuilds the object:

ruby
Rails.env = "production"
Settings.reload_from_files(
  Rails.root.join("config", "settings.yml").to_s,
  Rails.root.join("config", "settings", "#{Rails.env}.yml").to_s,
  Rails.root.join("config", "environments", "#{Rails.env}.yml").to_s
)

Notice what this call leaves out: the three local files. The example lists only the committed group, so a production check run this way ignores any developer override, which is usually what you want from a test of production values.

The cost of the global design shows up here. Nothing scopes the swap to one example, so a spec that calls reload_from_files changes Settings for every spec that runs after it unless you reload again. Restoring the original file list is up to the spec suite.

Reads are flexible. Settings.my_section.some_entry, Settings.my_section[:some_entry], Settings.my_section['some_entry'] and Settings[:my_section][:some_entry] are equivalent, and the bracket forms suit keys that are only known at runtime.

Version 5.x needs Ruby 2.6 or newer, and older Rubies are pushed to 1.x and 3.x

The current release line declares and tests Ruby 2.6 or newer, JRuby 9.2 or newer, TruffleRuby 19.3 or newer and Rails 5.2 or newer, along with Padrino and Sinatra. Anything older has to pin an old major version. Ruby 2.0 to 2.3 or Rails 3 to 4.1 should use version 1.x of the gem. Ruby 2.4 or 2.5, or Rails 4.2, 5.0 and 5.1, should use version 3.x. For older Rails or Ruby than that, the project points to AppConfig instead.

That is a real constraint for legacy apps. An app held back on Ruby 2.5 is on version 3.x, so check CHANGELOG.md in the repository for the release that introduced an option such as extra_sources before relying on it.

Recent releases are 5.6.1 and 5.6.0, both published on 11 July 2025, and 5.5.2 on 23 September 2024. The last push to the repository was on 28 July 2026, and the repository is not archived. The license field comes back as NOASSERTION from GitHub, with a LICENSE.md in the top-level listing, so read that file before shipping the gem in a product.

Editorial conclusion

Pick this gem when a Ruby app needs per-environment YAML with ERB and a per-developer override file, and the team is happy with a global Settings constant. Skip it if you need settings that cannot be reloaded from disk or a source other than files, hashes and objects with a load method. Before adopting, check which major version matches your Ruby and Rails, and confirm the license, because GitHub reports it as NOASSERTION and the repository carries a LICENSE.md.

Frequently asked questions

What does the rubyconfig config gem do?

It manages environment specific settings for Ruby projects. It reads layered YAML files, supports ERB inside them, and exposes the result through a global Settings object using member notation.

Which Ruby versions does the rubyconfig config gem support?

The current version is tested on Ruby 2.6 or newer, JRuby 9.2 or newer and TruffleRuby 19.3 or newer. Ruby 2.4 and 2.5 should use version 3.x, and Ruby 2.0 to 2.3 should use version 1.x.

How do I install the rubyconfig config gem on Rails?

Add the gem to the Gemfile, run bundle install, then run the rails g config:install generator. It creates config/initializers/config.rb and the default settings files.

Why is settings.local.yml ignored in the rubyconfig config test environment?

It is skipped in tests so local configuration cannot cause flaky or non-deterministic tests. Environment specific local files such as settings/test.local.yml are still loaded.

Official sources

  1. Issues
  2. README
  3. Releases
  4. rubyconfig/config on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rubyconfig-config.svg)](https://hysenlabs.com/projects/rubyconfig-config)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/rubyconfig-config.svg)](https://hysenlabs.com/projects/rubyconfig-config)

Was this useful?