Sinatra vs Rails — When I Reach for the Smaller Tool

by Arif Ikhsanudin, Backend Developer

The service that does not need generators

You are building a webhook receiver. It has three endpoints: one to receive events, one to replay them, one health check for your load balancer. Someone on your team is about to run rails new and you need to talk them out of it. Rails would technically work — it always does — but you would be shipping a service with an ORM, an asset pipeline skeleton, mailer stubs, and 40 megabytes of framework for a service with 200 lines of business logic. Sinatra is the right tool here.

What Sinatra is and is not

Sinatra is a DSL built on Rack. It gives you route matching, request/response handling, and helpers for rendering responses. It does not give you generators, an ORM, a standard directory layout, a testing infrastructure, or any of the other opinions Rails brings. That is the point.

# The whole application can live in one file for simple services
require 'sinatra'
require 'sinatra/json'
require 'json'

set :logging, true

post '/webhooks/events' do
  payload = JSON.parse(request.body.read)
  EventProcessor.new(payload).process
  json status: 'accepted'
end

post '/webhooks/replay' do
  event_id = params[:event_id]
  event = EventStore.find(event_id)
  halt 404, json(error: 'Event not found') unless event
  EventProcessor.new(event.payload).process
  json status: 'replayed'
end

get '/health' do
  json status: 'ok', version: ENV['APP_VERSION']
end

That is a deployable Sinatra application. No MVC, no config/ directory tree, no Gemfile with 60 transitive dependencies. Boot time is under a second. Memory footprint is around 30-50MB depending on what you pull in.

The cases where Sinatra earns its place

Internal APIs and service adapters: A service whose only job is to translate between two external API formats, validate payloads, and forward them. There is no domain model. There is no persistence layer. Rails would be waste; Sinatra is exactly right.

Lambda and edge function targets: When your deployment target is a serverless function or a Rack adapter on a CDN edge runtime, boot time and memory matter directly. Sinatra's 50MB baseline beats Rails' 150-200MB comfortably.

Prototyping API contracts: When you need to stand up a fake API server quickly for frontend development or integration testing, Sinatra's lack of ceremony is a feature. You write what you mean without plumbing.

High-traffic stateless endpoints: Sinatra's Rack layer is thin. For services that are pure compute — no database, no external calls — Sinatra can handle more requests per worker than Rails because the middleware stack is shorter. Benchmarks on a 4-core server (ApacheBench, 1000 concurrent connections, simple JSON response) show Sinatra at roughly 8,000-10,000 RPS versus Rails at 4,000-6,000 RPS per process. Neither is a bottleneck at typical loads, but the difference is real.

Where Sinatra will make you regret the choice

Sinatra has no routing namespace by default. For a service with 30 endpoints, your route file becomes hard to navigate without discipline. Rails' controllers and concerns provide a structure that scales with complexity. You can add sinatra-contrib for route namespacing and modular apps, but you are now building framework infrastructure instead of your product.

Database integration is entirely manual. Sinatra does not know what ActiveRecord is. You configure your own ORM connection, your own migration tooling, your own test fixtures. If you are using ActiveRecord anyway (which you can), you have lost most of Sinatra's simplicity while keeping its convention gaps. At that point, Rails is almost certainly the better host for ActiveRecord.

# Sinatra with ActiveRecord gets messy fast
require 'sinatra'
require 'active_record'

ActiveRecord::Base.establish_connection(
  adapter: 'postgresql',
  database: ENV['DB_NAME'],
  host: ENV['DB_HOST'],
  username: ENV['DB_USER'],
  password: ENV['DB_PASSWORD']
)

# You are now maintaining what Rails gives you for free

Authentication is another gap. Devise does not run on Sinatra. Rolling your own token auth in Sinatra is straightforward; rolling your own session-based auth with security hardening is not.

The practical line

Use Sinatra for services that have three characteristics: fewer than 15 routes, no database persistence layer or a simple one-table read-only query layer, and a clear single responsibility. Anything beyond that and Rails starts paying for its conventions.

The mistake I see most often is teams using Sinatra for something small that grows, and finding themselves six months later with a custom router, a custom ORM integration, a custom authentication middleware — in short, a poorly specified Rails. If you anticipate the surface area growing, start with Rails. If the service genuinely will not grow beyond its initial scope, Sinatra keeps it honest.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

What Actually Happens Inside a Database Transaction

Transactions provide atomicity and isolation, but understanding how they work mechanically — through write-ahead logs, lock acquisition, and MVCC snapshots — explains why certain patterns cause deadlocks, bloat, and unexpected performance cliffs.

Read more

How to Know If Your API Is Production-Ready

Shipping an API isn’t the hard part. Shipping one that doesn’t break under real users is. Here’s what separates “it works” from “it’s ready for production.

Read more

How to Politely Push Back on Unreasonable Demands

Clients can sometimes ask for the impossible—or the unreasonable. Here’s how to set boundaries without burning bridges.

Read more

The Hidden Expenses Every Remote Contractor Must Consider

Remote contracting sounds simple: work from anywhere, get paid, repeat. But behind the freedom is a list of costs most people don’t see coming.

Read more