A Rack application is typically configured through a config.ru (RackUp) file. This file defines the stack of middleware that will handle incoming requests before they reach the application itself.
One of Rack's core ideas is that applications are built from multiple layers. Each layer, called middleware, can inspect, modify, or respond to a request before passing it to the next layer in the stack.
When Rack builds the middleware stack, it passes each middleware instance the next layer through its initialize method. The last layer in the chain is the actual application.
Here's a simple example:
# config.ru
use Rack::Auth::Basic, "app" do |_, pass|
pass == "secret"
end
run proc {
[200, { "Content-Type" => "text/html" },
["Hello, world!"]]
}
The use keyword tells Rack which middleware class to instantiate and what arguments to pass to its constructor.
The run keyword specifies the final application that will handle the request.
Rack includes several built-in middleware components, such as:
-
Rack::Auth::Basic— HTTP Basic Authentication -
Rack::ContentType— Automatically sets the response content type -
Rack::ShowExceptions— Displays a helpful error page when an exception occurs
There are also many third-party middleware libraries available:
-
Rack::GoogleAnalytics— Injects Google Analytics tracking code -
Rack::Throttle— Adds request rate limiting -
Warden— A flexible authentication framework used by libraries such as Devise
One of Rack's strengths is that you can easily create your own custom middleware and insert it into the stack, allowing you to add application-specific behavior in a clean and reusable way.
Since Rails is built on top of Rack, every Rails application includes a config.ru file and uses Rack middleware internally.
For a deeper look at how Rails integrates with Rack, see the "Rails on Rack" guide in the Rails documentation.