Matthew Lang avatar

Sinatra

Sinatra is a minimal Rack-based DSL for building web apps — no forced structure, no ORM, no asset pipeline. Good for small apps, APIs, or when Rails would be overkill. Current major version (4.x) requires Ruby 3.0+ and Rack 3.

The classic style (single file)

require "sinatra"

get "/" do
  "Hello, world"
end

get "/posts/:id" do
  @post = Post.find(params[:id])
  erb :show
end

post "/posts" do
  Post.create(params[:post])
  redirect "/posts"
end

Run with ruby app.rb (spins up a dev server on port 4567) or via rackup.

require "sinatra/base"

class App < Sinatra::Base
  set :views, File.join(__dir__, "views")

  get "/" do
    "Hello, world"
  end
end
# config.ru
require_relative "app"
run App

Modular apps are just Rack apps — you can mount several together, and they don’t pollute the top-level namespace the way classic style does.

Routes

  • Verbs: get, post, put, patch, delete, options.
  • Named params: get "/posts/:id"params[:id].
  • Splat params: get "/say/*/to/*"params[:splat] (array).
  • Route conditions: get "/", host_name: "example.com" do ... end.

Request / response

get "/search" do
  params[:q]           # query string params
  request.body.read    # raw body
  content_type :json
  status 201
  headers "X-Custom" => "value"
end
  • halt 404, "Not found" — stop processing immediately.
  • redirect "/somewhere", 301
  • pass — decline the current route, fall through to the next matching one.

Views

Supports ERB, Haml, Slim, Builder, and others via Tilt. Templates live in views/ by default.

get "/" do
  erb :index, locals: { title: "Home" }
end

Layouts: views/layout.erb wraps templates automatically unless layout: false is passed.

Filters & settings

before do
  @user = User.find_by(id: session[:user_id])
end

after do
  logger.info "request completed"
end

configure :production do
  set :show_exceptions, false
end
  • set :name, value defines app-wide settings (sessions, public_folder, views, etc.).
  • enable :sessions turns on cookie-based sessions.

Middleware

Sinatra apps are Rack apps, so standard Rack middleware just works:

use Rack::Session::Cookie, secret: ENV["SESSION_SECRET"]
use Rack::Protection

Testing

Typically rack-test + Minitest or RSpec:

require "rack/test"

class AppTest < Minitest::Test
  include Rack::Test::Methods
  def app = App

  def test_root
    get "/"
    assert last_response.ok?
    assert_includes last_response.body, "Hello"
  end
end

When to reach for it

Good fit: small internal tools, webhooks receivers, JSON APIs, prototypes. If you find yourself building an ORM layer, a plugin system, and a background job runner on top of it, that’s usually a sign to move to Rails or Hanami instead.