DEV Community

Cover image for The Rails Initialization Process: From bin/rails to a Running Server
Shrouk Abozeid
Shrouk Abozeid

Posted on AI-assisted

The Rails Initialization Process: From bin/rails to a Running Server

When you run bin/rails server, Rails doesn't immediately start accepting HTTP requests.

It first loads dependencies, resolves the command, prepares the server, loads your application configuration, runs initializers, and builds the Rack application.

Let's walk through it.

1. Launching Rails

bin/rails

The journey starts with the bin/rails executable:

#!/usr/bin/env ruby

APP_PATH = File.expand_path("../config/application", __dir__)

require_relative "../config/boot"
require "rails/commands"
Enter fullscreen mode Exit fullscreen mode

The first line tells the operating system to execute the script using Ruby.

Next, Rails defines APP_PATH, which points to config/application.rb. This constant will be used later when Rails loads the application.

Then it requires two files:

  • config/boot.rb, to prepare the Ruby environment and dependencies.
  • rails/commands, to resolve and execute the requested Rails command.

Let's look at them one by one.

config/boot.rb

ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)

require "bundler/setup"
require "bootsnap/setup"
Enter fullscreen mode Exit fullscreen mode

This file prepares the application's dependency environment.

First, BUNDLE_GEMFILE tells Bundler which Gemfile to use, unless it has already been configured.

Next, bundler/setup configures Ruby's load path so the application can load the gems declared in the Gemfile.

Finally, bootsnap/setup enables Bootsnap's caching mechanisms to help reduce startup time.

At this point, the dependencies are ready to be loaded.

2. Resolving the Rails command

rails/commands.rb

After booting the dependency environment, Rails loads rails/commands.rb.

A simplified version looks like this:

require "rails/command"

aliases = {
  "g"  => "generate",
  "d"  => "destroy",
  "c"  => "console",
  "s"  => "server",
  "db" => "dbconsole",
  "r"  => "runner",
  "t"  => "test"
}

command = ARGV.shift
command = aliases[command] || command

Rails::Command.invoke command, ARGV
Enter fullscreen mode Exit fullscreen mode

ARGV contains the command-line arguments passed to the script.

For example, when you execute:

bin/rails server -p 3001
Enter fullscreen mode Exit fullscreen mode

Rails extracts server as the command and leaves -p 3001 as the remaining arguments.

If you use the shorthand s, Rails expands it to server.

It then calls Rails::Command.invoke to find and execute the appropriate command.

rails/command.rb

The Rails::Command.invoke method looks up the requested command and executes it when a matching command is found.

If Rails cannot resolve the command, it can fall back to invoking a Rake task with the corresponding name.

For our example, Rails resolves server to Rails::Command::ServerCommand.

You can explore the implementation in the Rails command source code.

3. Preparing the server

The server command is responsible for preparing the environment and starting the server.

A simplified version of its perform method looks like this:

def perform
  extract_environment_option_from_argument
  set_application_directory!
  prepare_restart

  Rails::Server.new(server_options).tap do |server|
    require APP_PATH
    Dir.chdir(Rails.application.root)

    if server.serveable?
      print_boot_information(server.server, server.served_url)
      server.start
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

The exact implementation can vary between Rails versions, but the important steps are the same.

First, Rails processes the environment option and prepares the application directory and restart behavior.

Then it creates a Rails::Server instance using the configured server options. These can include the host, port, environment, PID file, and server adapter.

Notice the order: the server object is created before APP_PATH is required.

This ordering matters because the server setup needs to establish the selected environment before the application is loaded.

What is Rails::Server?

In modern Rails, Rails::Server inherits from Rackup::Server.

Rackup provides the interface for running Rack applications, while Rails adds application-specific behavior around it.

The server object prepares the server configuration, but this doesn't mean that the Rails application has already completed initialization.

That happens in the next part of the process.

4. Loading the application configuration

When Rails executes:

require APP_PATH
Enter fullscreen mode Exit fullscreen mode

it loads your application's config/application.rb.

A typical Rails application contains something similar to:

require_relative "boot"
require "rails/all"

Bundler.require(*Rails.groups)

module MyApp
  class Application < Rails::Application
    # Application configuration
  end
end
Enter fullscreen mode Exit fullscreen mode

The actual file depends on your application and Rails version.

Let's break down the important parts.

Loading rails/all

require "rails/all"
Enter fullscreen mode Exit fullscreen mode

This loads the standard Rails frameworks, including Active Record, Action Controller, Action View, and other framework components.

Applications can choose a more selective set of frameworks, so the exact set depends on how the application was created and configured.

Defining Rails::Application

module MyApp
  class Application < Rails::Application
    # Application configuration
  end
end
Enter fullscreen mode Exit fullscreen mode

This defines your application class and its configuration.

For example, this is where you might configure time zones, autoload paths, middleware, generators, or other application settings.

However, defining the application class is not the same as fully initializing the application.

Rails still needs to execute the initialization process.

5. Building the Rack application

Now we reach Rails::Server#start.

The server startup process prepares runtime resources, handles development caching where applicable, configures logging, and delegates to Rackup to load and run the application.

For a standard Rails application, the Rack configuration file is config.ru:

require_relative "config/environment"

run Rails.application
Enter fullscreen mode Exit fullscreen mode

This file is the bridge between Rack and Rails.

Rackup uses Rack::Builder to evaluate the configuration file and build the Rack application.

The first line loads config/environment.rb.

Let's follow that call.

6. Initializing Rails

config/environment.rb

A standard Rails environment file looks like this:

require_relative "application"

Rails.application.initialize!
Enter fullscreen mode Exit fullscreen mode

The first line ensures the application configuration has been loaded.

The second line triggers the actual initialization process.

This is an important distinction:

config/application.rb defines the application; Rails.application.initialize! initializes it.

The initialization process is implemented through Rails' initializer infrastructure.

rails/all.rb and the Railties

When config/application.rb requires rails/all, Rails loads the framework components and their Railties.

A Railtie is an integration point that allows a framework or library to participate in Rails initialization and configuration.

Rails uses these integrations to register initializers, configure middleware, prepare framework components, and coordinate startup.

Running initializers

The initialize! method calls run_initializers, which executes the registered initializers in dependency order.

The initializers are organized into three broad groups:

  1. Bootstrap initializers: prepare the application and its environment.
  2. Railtie initializers: configure and integrate Rails frameworks, engines, and application-level behavior.
  3. Finisher initializers: perform later initialization work and finalize the application setup.

The ordering matters because some initializers depend on work completed by earlier ones.

For example, a framework may need its configuration to be loaded before another initializer uses it.

Application-specific initializers in config/initializers also participate in this process.

Once initialization finishes, Rails.application is ready to serve as the application object passed to Rack.

7. From Rails.application to the HTTP server

Remember this line in config.ru?

run Rails.application
Enter fullscreen mode Exit fullscreen mode

It tells Rack to use the Rails application as the Rack endpoint.

Rack builds the middleware application, and incoming requests pass through the configured middleware stack before reaching Rails' request-handling components.

The request eventually reaches the router and the relevant controller, depending on the application and request.

Meanwhile, Rackup starts the configured server adapter—typically Puma—which listens for HTTP connections and dispatches requests to the Rack application.

So there are two related but different responsibilities:

  • Rails initializes the application and prepares request-handling behavior.
  • Rackup and the server adapter provide the interface that runs the application and accepts HTTP requests.

That separation is one of the reasons Rails can run on different compatible Rack server implementations.

The complete flow

Here is the sequence in simplified form:

bin/rails
   |
   v
config/boot.rb
   |
   v
rails/commands.rb
   |
   v
Rails::Command.invoke
   |
   v
ServerCommand
   |
   v
Rails::Server
   |
   v
config/application.rb
   |
   v
server.start
   |
   v
Rackup loads config.ru
   |
   v
config/environment.rb
   |
   v
Rails.application.initialize!
   |
   v
Initializers run
   |
   v
run Rails.application
   |
   v
Rack middleware + server adapter
   |
   v
The application is serving requests
Enter fullscreen mode Exit fullscreen mode

The diagram is a conceptual overview rather than a complete call stack. Some steps invoke other setup routines, and the exact implementation can vary by Rails and Rackup version.

Final thoughts

Tracing Rails initialization helped me understand that starting a Rails server is not one operation. It's a sequence of responsibilities shared between the Rails command system, application configuration, the initializer infrastructure, Rack, and the server adapter.

If you want to explore the implementation further, the official Rails initialization guide is an excellent place to continue.

Understanding this flow is especially useful when debugging boot errors, investigating initializer order, or figuring out where a configuration change takes effect.

Top comments (0)