Getting Started with Hanami 2: Build Modern Ruby Web Apps
Hanami 2 is a modern Ruby framework that emphasizes simplicity, small memory footprint, and clean architecture. Unlike Ruby on Rails, Hanami takes a minimalist approach, building only what you need, when you need it. This guide walks you through installing Hanami 2 and creating your first application.
intro context
If you are getting started with Hanami 2, the first thing to understand is that the framework prefers small, explicit pieces over large, convention-heavy ones. That design affects everything you do, from installation to routing to the way actions and views stay separate. Once that pattern makes sense, the rest of Hanami becomes much easier to follow.
This guide focuses on the first hour of working with the framework. The aim is not to teach every Hanami feature at once, but to give you enough context to install the framework, create a project, and see how the main parts fit together.
Why choose Hanami?
Before we dive in, let’s understand what makes Hanami 2 special:
- Lightweight: Hanami ships with a fraction of Rails’ dependencies, giving you a faster, leaner framework
- Flexible: No forced conventions, organize your code your way, not the framework’s way
- Fast: Smaller footprint means faster boot times and lower memory usage, perfect for microservices
- Modern: Built for Ruby 3.2+ with native type annotations support and forward-thinking design
If you’re coming from Rails, Hanami might feel like a breath of fresh air, same Ruby goodness, but with more control over your application’s structure. Many developers find Hanami strikes a nice balance between Rails’ convenience and Sinatra’s simplicity.
The “why” matters here because framework choices shape the rest of your setup. If you know you want a small app, an API-first service, or a codebase that stays very explicit about its moving parts, Hanami is easier to appreciate once you connect those goals to the framework’s philosophy.
Installing Hanami 2
Hanami provides a convenient installer that sets up everything for you. Open your terminal and run:
gem install hanami
This installs the Hanami CLI and its dependencies. The installer handles all the heavy lifting, setting up the correct directory structure and configuration files. The gem install approach gives you the hanami command globally, so you can create new projects from any directory without additional setup.
Once installed, verify the version to confirm the CLI is working correctly:
hanami --version
You should see output similar to 2.0.0 or higher. If you see an error, make sure you have Ruby 3.2 or later installed, Hanami 2 requires a recent Ruby version.
That version check is worth doing right away because it saves time later. If the command fails here, you know the issue is with the local Ruby setup rather than with your app code. That makes troubleshooting much easier, especially if you are setting up a fresh machine or switching between projects.
Creating your first Hanami app
Now let’s create a new Hanami application. This is the moment you’ve been waiting for:
hanami new myapp
This command generates a fresh Hanami project with a clean directory layout. Unlike Rails, Hanami does not create dozens of files you may never touch. The scaffold includes only the essential directories, letting you add more structure as your application grows:
myapp/
├── app/
│ ├── actions/ # Request handlers
│ ├── views/ # View templates
│ └── models/ # Domain logic
├── config/
│ └── routes.rb # Routing configuration
├── db/ # Database migrations
└── spec/ # Test files
The structure is intentionally minimal. Actions, views, and models each get their own directory, and everything else is optional. This layout encourages you to think about which layers your app actually needs before adding them.
Navigate into your new project to start working with it:
cd myapp
You’ll notice the structure is cleaner than what you might be used to from Rails. There’s no app/controllers, app/helpers, or app/assets directories by default, you add what you need, when you need it.
That narrower structure is one of Hanami’s most noticeable differences. It gives you a clearer starting point because the app does not pretend to know which layers you will need yet. You can add new directories as the project grows instead of removing unused ones from a large default tree.
Starting the development server
Hanami includes a development server powered by Puma. Starting it is straightforward:
hanami server
By default, your app runs at http://localhost:3000. Open that URL in your browser, you should see the default Hanami welcome page. The server automatically reloads your code as you make changes, just like you’re used to with Rails.
One thing you’ll notice immediately is how fast the server starts. Because Hanami doesn’t load unnecessary dependencies, your app boots in seconds rather than the minutes you might expect from a larger framework.
That quick boot time is not just a nice extra. It changes how the development loop feels, because you spend less time waiting and more time reading the result of your last change. Smaller frameworks often feel more responsive for that reason, especially in early-stage projects.
Understanding Hanami’s architecture
Hanami follows a slightly different architecture than Rails. Understanding these differences will help you write better Hanami applications. Let’s break down the key components:
Actions
Actions handle HTTP requests. Each action is a class with a call method, this is similar to Rails controllers but more explicit:
# app/actions/books/index.rb
module Books
module Index
class Action < Hanami::Action
def call(params)
# Handle the request
end
end
end
end
Notice how each action is its own class. This makes testing easier and keeps your code modular. Unlike Rails where controllers can become massive, Hanami encourages small, focused action classes.
Each action is a self-contained object that receives a request and produces a response. You can test an action in isolation by passing a params hash and checking the output, without loading the entire application. This design also means you can reuse actions across different routes if needed.
Views handle responses. They receive data from actions and render templates in a format-agnostic way. In Hanami, views are completely separate from actions; this separation of concerns is intentional, this separation of concerns is intentional:
# app/views/books/index.rb
module Books
module Index
class View < Hanami::View
end
end
end
Views in Hanami can render multiple formats from the same view class, HTML, JSON, XML, and more. This makes building APIs straightforward.
Models
Models contain your business logic. In Hanami 2, you can use any persistence layer you prefer. ROM (Ruby Object Mapper) is the default, but you’re not locked in:
# app/models/book.rb
class Book < Hanami::Model::Entity
end
Hanami’s approach to models is refreshingly simple, entities are plain Ruby objects that represent your domain concepts.
Creating your first route
Routes define how URLs map to actions. Open config/routes.rb to see the default configuration:
# config/routes.rb
Hanami.configure do
root to: "home#index"
get "/books", to: "books#index"
get "/books/:id", to: "books#show"
end
The routing DSL is clean and expressive. After saving, the routes are automatically available, no restart needed during development. This is one of those quality-of-life features you’ll appreciate after using it.
This is also where Hanami starts to feel like a framework with strong boundaries. Routes point to actions, actions handle requests, and views handle output. That separation keeps each file narrower and makes it easier to find the right place for the next change.
Creating your first action
Let us create a simple “Hello World” action to see how everything connects. First, create the actions directory structure. Hanami expects each action to live in its own directory matching the module path:
mkdir -p app/actions/greetings
Now create the action file:
# app/actions/greetings/hello.rb
module Greetings
class Hello < Hanami::Action
def call(params)
self.body = "Hello, Hanami!"
end
end
end
The action inherits from Hanami::Action and defines a call method that receives the request parameters. Setting self.body is the simplest way to return a response. For more complex responses, you would typically use a view, but for a quick sanity check this direct approach works perfectly.
Add a route for it in config/routes.rb to connect the URL to the action. The route DSL maps the path to the action module, and the framework handles the rest. Visit http://localhost:3000/hello to confirm the connection works:
get "/hello", to: "greetings#hello"
Visit http://localhost:3000/hello, you should see “Hello, Hanami!” in your browser.
That small example is more important than it looks. It confirms that the application is wired together correctly, and it gives you a mental model for the rest of the framework: define a route, create an action, and let the browser show the result. Once that loop works, you can build on it with confidence.
Using Parameters
Actions can accept parameters from the URL. Let’s update our hello action to use query parameters:
# app/actions/greetings/hello.rb
module Greetings
class Hello < Hanami::Action
def call(params)
name = params[:name] || "World"
self.body = "Hello, #{name}!"
end
end
end
Now visit http://localhost:3000/hello?name=Ludwig, you’ll see “Hello, Ludwig!” displayed. The params object gives you clean access to all types of parameters, query strings, route parameters, and request body data.
That parameter flow matters because real applications spend most of their time accepting input and turning it into something useful. Hanami keeps the request data in one place so you do not have to guess where a parameter came from. That makes it easier to validate the input and easier to explain the action to someone else later.
When to use Hanami
Hanami excels in several scenarios:
- Microservices: Its small footprint makes it ideal for small services
- API-first applications: Building JSON APIs is straightforward
- Learning Ruby web development: The simpler architecture is easier to understand
- Performance-critical applications: Less memory and faster boot times matter
However, if you need the full-stack features of Rails or are working with a team that knows Rails well, the migration cost might not be worth it.
Common mistakes
- Trying to force Hanami into a Rails-shaped project structure.
- Skipping the Ruby version check and then debugging the wrong problem first.
- Adding too many layers before you have a working request-response loop.
- Treating the generated structure as a rigid rule instead of a starting point.
Frequently asked questions
Is Hanami hard to learn if I know Rails?
Not usually. The hardest part is often adjusting to the smaller default structure. Once you accept that the framework wants explicit boundaries, the pieces are straightforward.
Should I use Hanami for every Ruby web app?
No. Hanami is a strong fit when you want a lightweight, modular app, but Rails is still a better choice for some teams and projects. The right framework depends on the shape of the work and the size of the ecosystem you want around it.
What should I learn after this guide?
The best next steps are actions and views, then persistence. That sequence teaches you how requests flow through the app before you add database code, which keeps the learning curve gentler.
What’s Next?
You’ve just created your first Hanami 2 application! Here’s what to explore next:
- Actions and Views: Learn how to render HTML, JSON, and other formats
- Database Persistence: Set up ROM for working with databases
- Slices: Organize larger applications into modular slices
forward-link
If you want to keep going in this Hanami basics series, the next guide is Actions and Views in Hanami. That page shows how request handling and rendering fit together once the app is up and running.
The next tutorial in this series covers Actions and Views in Hanami, where you’ll learn how to build complete request-response cycles with proper data flow between layers.
Happy coding!
See also
- Actions and views in Hanami — building request-response cycles with proper data flow
- Hanami ROM persistence — setting up database access
- Hanami slices — organizing larger applications into modular slices