Getting Started with Sinatra: Build Your First Ruby Web App
If you are getting started with Sinatra, this lightweight web framework lets you build web applications in Ruby with minimal fuss. Unlike Rails, which comes with every feature you could imagine, Sinatra gives you just what you need and nothing more. This makes it perfect for small projects, APIs, and learning how web frameworks work under the hood.
In this tutorial, you’ll install Sinatra, create your first app, learn about routing, work with views, and serve static files.
Intro context
Sinatra is a great place to start if you want to understand how a Ruby web app responds to a browser request without absorbing the entire Rails stack at once. The framework keeps the moving parts small, which makes the request flow easier to see and easier to reason about.
That simplicity is also what makes Sinatra a strong teaching tool. You can define a route, return a string or template, and immediately see the result in a browser. The feedback loop is short, which means you spend more time learning the shape of the app and less time on framework ceremony.
If you later move to a larger framework, the ideas here still transfer. Routes, templates, static files, and request parameters all show up again, just with more helpers around them. Learning the basics here gives you a vocabulary that will keep paying off.
One useful way to approach this tutorial is to treat each section as a tiny checkpoint. Install Sinatra, make the first route work, then add one more feature at a time. That keeps the examples small enough to understand and makes it easier to spot where a change actually happened.
Another good habit is to keep the browser open while you work. Sinatra is easiest to learn when you can make one small change, refresh the page, and see exactly how the response changed. That tight feedback loop turns the framework into something you can experiment with instead of something you have to memorize all at once.
Installation
Before installing Sinatra, make sure you have Ruby installed on your system. If you don’t, check out our Installing Ruby guide.
Sinatra is distributed as a gem, so you install it like any other Ruby library:
gem install sinatra
Or add it to your Gemfile if you’re using Bundler:
The important thing is not that the first example is impressive but that it proves the whole stack works. If something goes wrong here, keep the example small and test one layer at a time: check the file name, confirm the route pattern, and inspect the browser output before adding more complexity.
gem 'sinatra'
That’s it! You’re ready to build web applications.
The important thing is not that the first example is impressive. It is that the first example proves the whole stack is working: Ruby loaded, Sinatra loaded, a route was matched, and the browser received a response.
If something goes wrong here, keep the example small and test one layer at a time. Check the file name, check the route, and check the browser output before you move on. That habit will save you time later when the app has more moving parts.
Your First Sinatra App
Create a new file called app.rb and add the following code:
require 'sinatra'
get '/' do
'Hello, World!'
end
Run your application:
This is the first time the app starts to feel dynamic. Instead of hard-coding one response, the route can react to URL segments and user-provided data, which is the same pattern you use in much larger web applications. Route parameters let you build pages that respond to different inputs without writing a separate route for every possible value.
ruby app.rb
You should see output indicating the server is running. Open your browser and visit http://localhost:4567. You should see “Hello, World!” displayed.
Let’s break down what just happened:
require 'sinatra'loads the Sinatra framework into your applicationget '/'defines a route that responds to GET requests at the root URL- The string returned by the block is sent as the response
You can also return HTML directly:
get '/' do
'<h1>Hello, World!</h1><p>Welcome to my Sinatra app</p>'
end
Routing Basics
Routing in Sinatra maps URLs to code that handles requests. You define routes using HTTP methods: get, post, put, delete, and patch.
Templates become valuable as soon as the HTML grows beyond a single line. They let you separate presentation from route logic, which keeps the Ruby code easier to test and the HTML easier to edit. As your app expands, templates also make it easier to reuse layout structure by keeping a common header and footer in one place.
get '/hello' do
'This is a GET request'
end
post '/hello' do
'This is a POST request'
end
get '/users/:name' do
"Hello, #{params[:name]}!"
end
The :name in the route is a parameter you can access through the params hash. Visit /users/Alice and you’ll see “Hello, Alice!”.
That is the first time the app starts to feel dynamic. Instead of hard-coding one response, the route can react to the URL and the data a user provides. That is a small step, but it is the same pattern you use in much larger web apps.
This pattern also shows why route parameters matter so much in real applications. Once you understand how to read values from the URL, you can build pages that respond to users, records, and search terms without writing a separate route for every possible case.
You can also capture multiple segments:
get '/books/*/author/*' do
"Book author: #{params[:splat].last}"
end
Route parameters are useful for building RESTful APIs and dynamic web pages.
Views with ERB
Returning strings from routes works for simple cases, but most applications use templates to keep their code organized. Sinatra supports many template engines, and ERB (Embedded Ruby) is the most common.
Create a folder called views and add a file called hello.erb:
<h1>Hello, <%= @name %>!</h1>
<p>Welcome to my Sinatra application.</p>
Update your route to render this template:
That convention is simple but easy to forget when you first add styles or JavaScript to a Sinatra project. Once you remember that the public directory is automatically exposed at the root path, the rest of the asset setup is usually straightforward. This is also the point where the app starts to feel like a small but real project.
require 'sinatra'
get '/hello/:name' do
@name = params[:name]
erb :hello
end
The @name instance variable is available in your ERB template. The erb :hello line looks for views/hello.erb.
Templates become valuable as soon as the HTML gets a little longer than a single line. They let you separate presentation from route logic, which keeps the Ruby code easier to test and the HTML easier to edit.
As your app grows, templates also make it easier to reuse layout structure. You can keep a common header, footer, or navigation area in one place and let each route focus on the content it needs to show.
You can also pass a layout file for consistent page structure. Create views/layout.erb:
<!DOCTYPE html>
<html>
<head>
<title><%= @title || 'My App' %></title>
</head>
<body>
<%= yield %>
</body>
</html>
Wrap your content in yield tags, and Sinatra automatically uses the layout.
Static Files
Most web applications need to serve CSS, JavaScript, and images. Sinatra makes this easy by default—any files in a public folder are served automatically.
Create the structure:
your-app/
├── app.rb
├── public/
│ ├── style.css
│ └── script.js
└── views/
└── hello.erb
Reference these files in your views:
At this point you have the three pieces that most small Sinatra apps need: a route to handle the request, a template to render the response, and a place for static files. Keeping those pieces separate makes the code easier to extend because each one has one clear responsibility and does not bleed into the others.
<link rel="stylesheet" href="/style.css">
<script src="/script.js"></script>
The /public part of the path is omitted because Sinatra serves from that directory by default. This is perfect for assets that don’t change often.
That convention is simple, but it is easy to forget the first time you add styles or JavaScript. Once you remember that public is automatically exposed, the rest of the asset setup usually becomes straightforward.
This is also the point where the app starts to feel like a small real project. Routes handle requests, templates handle HTML, and the public folder handles assets. That split is simple, but it gives the app just enough structure to stay organized.
At this point you have the three pieces that most small Sinatra apps need: a route, a template, and a place for static files. Keeping those pieces separate makes the code easier to extend because each one has one clear job.
Next Steps
You’ve built a working Sinatra application from scratch. Here’s what to explore next:
- Sessions and cookies - Track user data across requests using
enable :sessions - Helpers - Extract shared logic into helper methods
- Models - Connect to a database using ActiveRecord or ROM
- Deployment - Deploy to Heroku, Render, or any Ruby-friendly host
Sinatra is flexible enough to grow with your project but simple enough to understand in an afternoon. Start small, iterate quickly, and enjoy building web applications the Ruby way.
If you keep experimenting, try combining one new route, one template, and one static asset at a time. That keeps the examples small enough to understand while still showing you how a real Sinatra app grows.
The next time you need to explain Sinatra to someone else, start with these building blocks instead of the framework name. Route, template, static file, and request parameter are the ideas that matter, and they are the easiest way to remember how Sinatra fits together.
The bigger lesson is that Sinatra removes almost all of the ceremony from web development while keeping the important pieces visible. You still have routes, requests, responses, and templates, but the framework stays small enough that you can see how each part fits together as you learn.
Forward link
If you want to go one layer deeper, continue with Rack Middleware from Scratch and Building a Web Framework. Those tutorials show the request cycle underneath Sinatra, which makes the framework feel less like magic and more like a small, readable wrapper around Rack.
That perspective is useful when you need to debug a route, explain how a response is built, or decide whether a problem belongs in Sinatra itself or in the code behind it.
See Also
- Installing Ruby - Set up your Ruby environment
- Ruby Basics: Variables and Types - Fundamental Ruby concepts
- Ruby Methods - Defining and using methods in Ruby
- Ruby Hashes - Working with key-value data structures
- Ruby Arrays - Collections and iteration in Ruby