Configuring Rails Environments
Despite its strong opinions and powerful conventions, Rails is a highly flexible and configurable framework. If you don’t like something, there’s almost certainly a way to change it. This article provides a brief overview of configuring Rails applications and environments.
All Rails applications come with three environments out of the box:
production. In addition, you can also create your own environments for staging, QA, or continuous integration.
All these environments are highly customizable. They share a few standard settings and can have their own, custom settings, which allow you to configure things like your database connection, error handling mechanism, logging level and format, security-related settings, and much more.
In this post, we will learn how Rails environments work, and some of the useful configuration settings you can use to customize them. It doesn't cover all the configuration settings, but the most important ones that you'll often run into.
Here're the topics this article covers:
- About your Rails application
- How to create and use a specific environment
- Figure out the current environment
- Using gems specific to an environment
- Using Rails initializers for configuration
- Common configuration settings in Rails
All Rails configuration-related files live under the
config directory and most of the options are well-documented, either in code, guides, or the API. So feel free to browse the files and get familiar with the powerful settings available to you.
We'll start by inspecting a handy Rails command that gives a birds-eye view of your application environment.
About Your Rails Application
about command in Rails gives you a quick overview of your application and the current environment. It lists the versions of various components (Ruby, Rack, etc.), print all the middleware, and other useful information like database adapter.
➜ railsway git:(main) ✗ bin/rails about About your application's environment Rails version 18.104.22.168 Ruby version ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-darwin21] RubyGems version 3.3.26 Rack version 22.214.171.124 Middleware ActionDispatch::HostAuthorization, Rack::Sendfile, ActionDispatch::Static, ActionDispatch::ServerTiming, ..., Rack::Head, Rack::ConditionalGet, Rack::ETag, Rack::TempfileReaper Application root /rails/railsway Environment development Database adapter sqlite3 Database schema version 0
P.S. I just learned this while writing and researching this article, after reading about Laravel's
php artisan about command, which is pretty cool.
How to Create and Use a Specific Environment
You can specify the current environment using the
RAILS_ENV environment variable. Its value is set to the name of one of the configuration files under the
config/environments folder, i.e.
test. You can also create a
staging.rb file in the
environments directory and set
RAILS_ENV variable is not set, Rails checks the
RACK_ENV to figure out the current environment. If that isn't set either, Rails assumes the environment is
development by default. Rails will automatically set the
test when running tests (see
That means you don't have to set this environment variable during development or testing. The only time you have to worry about setting the environment variable is on your production server.
Sometimes, you may want to set up additional environments to set up a CI/CD pipeline or use a Staging server, before you deploy to production. In this case, all you have to do is copy and paste one of the existing configuration files in the
config/environments folder and rename it to the new environment, e.g.
staging.rb. Then configure it however you want with the settings described below.
Figure out the Current Environment
You can check the current environment using the
➜ bin/rails c Loading development environment (Rails 126.96.36.199) irb(main):001:0> Rails.env "development"
Rails also provides a bunch of useful helpers allowing you to assert a specific environment.
➜ irb(main):002:0> Rails.env.production? false ➜ irb(main):003:0> Rails.env.development? true
Behind the scenes, it uses the
EnvironmentInquirer which extends
StringInquirer to enable these helpers.
# railties/lib/rails.rb:71 def env @_env ||= ActiveSupport::EnvironmentInquirer.new(ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || "development") end
This code also shows the sequence and priority of how Rails checks for the environment. As we saw in the previous section, it will first check
RACK_ENV and finally, it will assume
Using Gems Specific to an Environment
The root of your Rails application contains a
Gemfile which lists all the Ruby gems your application depends on, including the Rails gem.
# frozen_string_literal: true source "https://rubygems.org" gemspec gem "rake", ">= 13" gem "stimulus-rails" gem "turbo-rails"
If you want to load a gem only in a certain environment, you can scope it using the
# load `rake` in all environments gem "rake" # load `minitest` only in the `test` environment group :test do gem "minitest" end # load `debug` in both `test` and `development` environments group :test, :development do gem "debug" end
When the Rails application loads, it requires all the gems listed in the
Gemfile, including any gems you've limited to the specific environment.
Using Rails Initializers for Configuration
An initializer is simply a piece of Ruby code under the
config/initializers directory. You can use initializers to configure your Rails application or external gems.
To learn more about Rails initializers, check out the following post:
Out of the box, Rails provides following initializers:
assets.rb: configures the asset pipeline.
content_security_policy.rb: defines an application-wide content security policy.
filter_parameter_logging.rb: configures the parameters to be filtered from the log file.
inflections.rb: adds new inflection rules.
permissions_policy.rb: defines an application-wide HTTP permissions policy.
Since Rails loads initializers after the application and external gems are loaded, initializers provide a great place to configure the application as well as the gems. You can find a comprehensive list of all initializers in Rails on the official Rails guides.
Common Configuration Settings in Rails
This section covers some of the important configuration settings that are common to most Rails applications. After inspecting the common settings, we'll dive into environment-specific configuration.
config/application.rb file contains the common application configuration for all environments.
# config/application.rb module Blog class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 7.0 # Configuration for the application, engines, and railties goes here. # # These settings can be overridden in specific environments using the files # in config/environments, which are processed later. # # config.time_zone = "Central Time (US & Canada)" # config.eager_load_paths << Rails.root.join("extras") end end
Note: The configuration settings defined in the
config/environments/*.rb files take precedence over the ones defined in the
config/application.rb file, as those files are loaded after loading the framework and all the gems.
Additional Common Settings
config.time_zone allows you to configure the time zone for your application. It's set to UTC by default.
config.generators lets you configure the Rails generators to avoid having to provide command-line flags repeatedly.
config.generators do |g| g.orm :data_mapper, migration: true g.template_engine :haml g.test_framework :rspec end
config.log_level overrides the default log level, which is
:debug. You can set different log levels in different environments, depending on your needs.
config.log_level = :info
config.active_record.schema_format specifies the format to use when dumping the database schema.
config.active_record.schema_format = :sql
config.autoload_paths provides the array of directories from which we autoload and reload, if reloading is enabled. You can add other directories to this path, if needed.
It's often helpful to have different configuration settings based on the environment where the application is running. For example, you may want to use a different Active Storage service in production than the one you're using in development.
Rails allows you to define environment-specific configuration settings in the appropriately named files in the
config directory, e.g. the
config/environments/test.rb file contains all the settings used in the
This is the default Rails environment. You can find all the settings specific to this environment in the
The great thing about Rails is the quick feedback loop. Make a change, reload the browser, and see your change. This setting controls if the code should be reloaded any time it changes.
It's set to
false in development mode, as we do want the code to be reloaded. However, it's enabled in production, as we won't be editing code in production and reloading adds extra cost.
When the application boots, Rails can eager load all the code. This is great for production (where this setting is enabled), but not so much for development.
You'll be continuously changing the code in development, and there's no point in eager loading the code, which increases the boot time. Hence it's set to
false in development mode.
In development, if something goes wrong, you need to see all the details regarding the request, form data, backtrace, line numbers, etc. However, in production, your users don't need this information. All they'll need is a nice error page.
This setting, when enabled prints a developer-friendly message that includes all the information needed for debugging. Set to
true in development mode, but
false in production.
During development, it's important to see how long a certain request took. The
Server-Timing header communicates this information for a given request-response cycle, which you can inspect in the Network tab in DevTools.
server_timing setting, when enabled, adds the
ActionDispatch::ServerTiming middleware in the middleware stack. It subscribes to all
ActiveSupport::Notifications and adds their duration to the
This is a relatively new setting that was introduced in Rails 7.
Caching lets you save data generated during the request-response cycle and reuse it when responding to similar requests.
By default, caching is only enabled in your production environment. You can play around with caching locally by running
rails dev:cache, or by setting
This setting tells Active Storage which service to use. Since each environment will use a different service (
local in development,
s3 in production, etc.), it is recommended to do this on a per-environment basis.
In development, it's sufficient to store the uploaded files locally. Hence, it's set to
:local service, which is defined in the
You must have seen the error Rails shows you when you try to run the app after adding a migration, but forget to run it. This setting controls this functionality.
In development, it's set to
:page_load, which instructs Rails to insert the
CheckPending middleware into the middleware stack. This middleware verifies that all migrations have been run before loading a web page.
When set to
true, this setting tells Rails to highlight the code that triggered database queries in logs.
When set to
true, this suppresses logger output for the asset requests. In development mode, it's not really useful. If necessary, you can turn it on for debugging purposes.
In test mode, this setting is set to
true. It configures the public file server for tests with Cache-Control for performance.
Under the hood, it includes the
ActionDispatch::Static middleware in the middleware stack. This middleware serves static files from disk, if available. If no file is found, it hands off to the main app.
In the test mode, this setting is typically set to false, to avoid having to load your whole application. However, you might need it while running the tests on continuous integration servers.
This disables request forgery protection, which protects you from cross-site request forgery attacks. You don't need this in the test environment.
We set this to
true in production, as we don't have to reload the code between requests.
Again, this is set to
true as we do want to eager load all the code in memory once the application starts.
By default, this setting is disabled. Typically, your web server (Apache or Nginx) handles this without involving the Rails app. However, you can enable it if that's not the case.
The Asset Pipeline precompiles the assets in production. We don't want live compilation on production as it's slow, lacks compression, and will impact the render time of the pages. [source]
This is set to
:info in production to avoid logging too much information. We don't want to accidentally expose personally identifiable information.
[:request_id] in production to prepend all log lines with the request id.
I could go on, but will just stop here. This is not a complete set of all Rails config settings, but just the important ones that you get out-of-the-box when you generate a new app. For a complete list, check out Rails docs on Configuring Rails Applications.
I hope you found this article useful and that you learned something new.
If you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I look forward to hearing from you.
Please subscribe to my blog if you'd like to receive future articles directly in your email. If you're already a subscriber, thank you.