Reason #171 • June 20th, 2026

Rack

One of the most fundamental pieces of Ruby web development is Rack, a tiny interface sitting between web servers and web applications. It is used by all the major Ruby web frameworks like Rails, Sinatra, Hanami and Roda, and is supported by all major server implementations like Puma and Falcon.

A Rack app is any Ruby object that responds to call, which receives an environment hash for the request, and returns an array with three parts: status, headers and body.

That's it!

Rack servers read "rackup" config.ru files by default, which are just Ruby files that bootstrap Rack applications. They are evaluated with self set to a Rack::Builder instance, which provides a DSL with methods like use to add middleware and run to set the app to run. A simple rackup file can look like this:

Ruby (config.ru)
run do |env|
  body = "You requested #{env['REQUEST_METHOD']} #{env['PATH_INFO']}\n"

  [
    200,
    { "content-type" => "text/plain" },
    [body],
  ]
end
    

Run it with rackup and request a path:

$ curl http://localhost:9292/hello
You requested GET /hello

Middleware can be defined as a class that takes an app in the initializer and implements #call to do something before or after calling the next app in the chain. For example, we can add a header with the request time:

Ruby (config.ru)
class RuntimeHeader
  def initialize(app)
    @app = app
  end

  def call(env)
    started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    status, headers, body = @app.call(env)
    elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at

    headers["x-runtime"] = "#{(elapsed * 1000).round(1)}ms"

    [status, headers, body]
  end
end

use RuntimeHeader

run do |_env|
  [200, { "content-type" => "text/plain" }, ["Hello, Rack!\n"]]
end
    

It's just calls all the way down!

History

The first version of Rack, 0.1.0, shipped on March 2, 2007.

Rack 1.0.0 was finalized on April 24, 2009.

Rack is still evolving, with the latest major version 3.0 released in September 2022, with better support for async servers and streaming responses, among other improvements.

Reason #172 ?