Skip to main content

A Comparative Analysis: Hanami vs. Sinatra for Building Lightweight Ruby Applications

When you're building a lightweight Ruby application, the framework choice often comes down to two names: Hanami and Sinatra. Both are celebrated for their minimal footprint, but they serve very different long-term strategies. This guide is for developers and technical leads who need to decide not just which framework to start with, but which one will still feel right after six months of feature growth. We'll compare them through a lens of sustainability—how each framework handles change, scales with team size, and shapes your codebase's ethical relationship with complexity. Who Must Choose and by When This decision typically lands on a small team—maybe three to five developers—starting a new service, API, or micro-app. You have a clear domain but an uncertain feature roadmap. The pressure is to ship fast, but you also know that rewrites are expensive. The deadline is often in weeks, not months.

When you're building a lightweight Ruby application, the framework choice often comes down to two names: Hanami and Sinatra. Both are celebrated for their minimal footprint, but they serve very different long-term strategies. This guide is for developers and technical leads who need to decide not just which framework to start with, but which one will still feel right after six months of feature growth. We'll compare them through a lens of sustainability—how each framework handles change, scales with team size, and shapes your codebase's ethical relationship with complexity.

Who Must Choose and by When

This decision typically lands on a small team—maybe three to five developers—starting a new service, API, or micro-app. You have a clear domain but an uncertain feature roadmap. The pressure is to ship fast, but you also know that rewrites are expensive. The deadline is often in weeks, not months. In this pressure cooker, the framework you pick will either accelerate your early velocity or become the first source of friction.

We've seen teams default to Sinatra because it's familiar and minimal, only to hit a wall when the app grows beyond a handful of routes. Others choose Hanami, drawn by its promise of clean architecture, but struggle with its steeper initial setup. The key is to match the framework to the type of complexity you expect, not just the current size. Ask yourself: will this application handle multiple bounded contexts? Do you need a clear separation between business logic and web delivery? Will the team grow by two or three people in the next year? Your answers should guide your choice.

If you're building a prototype that will be thrown away, Sinatra is the obvious pick. If you're building a system that will evolve into a core product, Hanami's structure might save you from a painful rewrite. The timeline matters too: if you need a working demo in two days, Sinatra's simplicity wins. If you have a month to build a well-structured v1, Hanami's learning curve is manageable.

The Cost of Switching Later

One hidden factor is the cost of migrating from one framework to another. Moving from Sinatra to a more structured framework later often means rewriting the entire application logic because routes, models, and views are tightly coupled. Hanami, with its modular design, allows you to extract components incrementally. This sustainability angle—how easily can you change your mind?—is often overlooked in early decisions.

The Option Landscape: More Than Two Choices

While this article focuses on Hanami and Sinatra, they are not the only lightweight Ruby options. Understanding the full landscape helps you see why these two represent distinct philosophies. At one extreme is Rack itself: raw middleware composition with no framework. At the other is Rails, which is not lightweight but offers convention over configuration. In between, you have Sinatra, Hanami, and a few others like Cuba or Roda.

Sinatra is a DSL for creating web applications with minimal ceremony. It's essentially a thin wrapper around Rack, giving you routing, request handling, and a templating system. Its philosophy is 'just enough'—you add components as you need them. This makes it ideal for small APIs, webhooks, or single-purpose services. However, as you add features, you must manually impose structure. Without discipline, Sinatra apps can devolve into a single file with hundreds of lines of routes and inline logic.

Hanami, formerly Lotus, takes a different approach. It's a full-stack framework that embraces clean architecture principles: entities, repositories, actions, and views are separate concerns. It provides a built-in dependency injection container, a robust router, and a modular structure that encourages isolating business logic from the web layer. Hanami is not a micro-framework—it's a lightweight framework with opinions about how your code should be organized. This makes it more suitable for applications that will grow in complexity, but it also means a steeper initial learning curve.

Cuba and Roda are even more minimal than Sinatra, focusing on routing performance and simplicity. They are excellent for extremely small services or when you need maximum throughput. However, they lack the ecosystem and community support that Sinatra and Hanami enjoy. For most teams, the choice narrows to Sinatra or Hanami because they offer the best balance of simplicity and capability.

Why Not Rails?

Rails is the elephant in the room. It's powerful, but it's not lightweight. If you're reading this, you likely have a reason to avoid Rails: maybe you want a smaller deployment footprint, faster boot times, or a simpler mental model. Both Hanami and Sinatra boot significantly faster than Rails, making them attractive for microservices or serverless environments. They also use less memory, which can reduce hosting costs. But remember: Rails' conventions reduce decision fatigue. The trade-off is that you trade initial simplicity for long-term structure. Hanami tries to give you that structure without the weight, while Sinatra leaves it entirely up to you.

Comparison Criteria You Should Use

To compare Hanami and Sinatra fairly, you need criteria that reflect real-world use, not just feature checklists. We recommend evaluating on four axes: application complexity, team size and experience, testing philosophy, and deployment environment. Each axis reveals a different strength.

Application complexity is about the number of distinct domains, not lines of code. A Sinatra app with 20 routes that all touch the same model is simple. A Hanami app with 5 routes that span multiple bounded contexts is complex. If your app has multiple subdomains (e.g., billing, user management, analytics), Hanami's modular structure helps you keep them isolated. Sinatra would require you to manually create modules and separate files, which is possible but not enforced.

Team size and experience matter because frameworks enforce different levels of discipline. A solo developer or a pair can manage Sinatra's freedom. A team of five or more will benefit from Hanami's conventions, which reduce the need for style guides and code reviews. However, if your team is new to Ruby, Sinatra's simplicity is easier to learn. Hanami's concepts—entities, repositories, dependency injection—require a higher upfront investment.

Testing philosophy is often overlooked. Sinatra apps are typically tested with Rack::Test, which is fast but encourages integration tests that hit the full stack. Hanami, with its separation of actions and business logic, naturally leads to more unit tests and isolated integration tests. If you value a test pyramid with many unit tests, Hanami's architecture supports that. If you prefer end-to-end tests with fewer mocks, Sinatra's simplicity might be sufficient.

Deployment environment includes serverless platforms, containers, and traditional servers. Sinatra's minimal footprint makes it ideal for AWS Lambda or Google Cloud Functions, where cold start time matters. Hanami boots a bit slower, but still faster than Rails. Both work well with Docker. The choice here often comes down to memory constraints: Sinatra uses about 30-40 MB, while Hanami uses 50-70 MB. For most applications, this difference is negligible, but for high-density deployments, it could tip the scale.

How to Weight These Criteria

Not all criteria are equal. If your application is a simple CRUD API, complexity is low, and team size is small—Sinatra wins. If you're building a multi-tenant SaaS with separate billing and analytics modules, complexity is high, and Hanami's structure pays off. The key is to be honest about your future trajectory, not just your current state.

Trade-offs Table: Hanami vs. Sinatra

The following table summarizes the key trade-offs between Hanami and Sinatra across several dimensions. Use it as a quick reference when discussing with your team.

DimensionSinatraHanami
Learning curveLow (hours)Medium (days)
Boot time~100 ms~300 ms
Memory footprint~30 MB~60 MB
Built-in structureNone (manual)MVC + clean architecture
Testing paradigmIntegration-heavyUnit-heavy
EcosystemLarge (many gems)Smaller but growing
Best forSmall APIs, webhooks, prototypesMulti-domain apps, long-lived projects
Worst forComplex apps without disciplineQuick prototypes or throwaway code

This table highlights that Sinatra is not 'worse' than Hanami—it's just optimized for different constraints. The danger is when you apply Sinatra to a problem that needs Hanami's structure, or vice versa. The most common failure we see is a Sinatra app that grew organically into a tangled mess of routes and middleware, where a simple change breaks three endpoints. Hanami prevents that by forcing you to separate concerns from day one.

When the Table Doesn't Tell the Whole Story

Trade-offs tables can oversimplify. For instance, Sinatra's large ecosystem means you can find gems for authentication, background jobs, and caching. Hanami has fewer official extensions, but its modular design lets you integrate any Rack middleware or Ruby library. The real difference is in how you compose these pieces. With Sinatra, you often glue them together in a single file or a few modules. With Hanami, you inject them via the dependency container, which makes swapping implementations easier for testing or configuration.

Implementation Path After the Choice

Once you've chosen a framework, the implementation path differs significantly. For Sinatra, we recommend starting with a single app.rb file and refactoring early. As soon as you have more than 10 routes or 200 lines, extract route handlers into separate files using Sinatra's namespace or register helpers. Organize by resource: users.rb, orders.rb, etc. Use Sinatra::Base for modular apps instead of the top-level DSL. This gives you the flexibility to compose multiple Sinatra applications under a single Rack stack.

For Hanami, the implementation path is more prescriptive. Start with hanami new, which generates a project structure with apps/, lib/, and spec/. Define your entities in lib/ and repositories that wrap database access. Actions go in apps/web/controllers/. Views are separate objects in apps/web/views/. This separation means you can test business logic without loading the web stack. We recommend writing entity and repository tests first, then actions and views. This bottom-up approach aligns with Hanami's architecture and catches domain errors early.

Both frameworks require you to think about middleware early. In Sinatra, you add middleware in the app class. In Hanami, you configure middleware in the application configuration file. For common tasks like authentication, logging, and error handling, Sinatra's middleware stack is simpler to set up. Hanami's dependency injection makes it cleaner to inject services like a user repository into your authentication action.

Deployment Checklist

Regardless of framework, your deployment checklist should include: set environment variables, configure database connections, precompile assets (if any), and ensure Rack-compatible server (Puma, Unicorn). For Sinatra, you might need to add gems for asset pipeline or background jobs manually. For Hanami, many of these are built-in or have official guides. Both benefit from containerization with Docker to ensure consistency across environments.

Risks If You Choose Wrong or Skip Steps

Choosing the wrong framework can cost you weeks of refactoring or a complete rewrite. The most common risk with Sinatra is under-structuring. Teams start with a simple app, but as features pile up, the codebase becomes a monolith of global state and tangled dependencies. Debugging becomes a nightmare because a change in one route can affect others through shared variables. This is not Sinatra's fault—it's a consequence of not imposing structure. The fix is to refactor early, but many teams delay until it's too painful.

With Hanami, the risk is over-engineering. You might spend hours setting up entities, repositories, and dependency injection for a simple CRUD app that could have been written in Sinatra in a day. This upfront cost can kill momentum, especially for prototypes. Another risk is the smaller ecosystem: if you need a specific gem that only works with Rails or Sinatra, you might have to build a wrapper. Hanami's conventions also mean that if you deviate from them, you lose the benefits of the framework.

Skipping steps is another danger. For Sinatra, skipping the refactoring step leads to technical debt. For Hanami, skipping the learning step leads to misusing the framework—like putting business logic in actions instead of entities. Both scenarios result in code that is harder to maintain than if you had chosen the other framework.

How to Mitigate These Risks

To mitigate Sinatra's risk, enforce code review standards that require separation of concerns. Use modules and service objects from the start. To mitigate Hanami's risk, start with a small, well-defined feature and expand. Don't try to build the perfect architecture on day one. Also, invest in learning the framework's idioms through its official guides and community forums.

Mini-FAQ

Is Hanami faster than Sinatra in production?

Not necessarily. Both are fast enough for most applications. Hanami has a slightly slower boot time but comparable request throughput. The real performance difference comes from your code, not the framework. If you need extreme performance, consider Roda or Cuba, but for typical web apps, either is fine.

Can I use Hanami gems in Sinatra?

Yes, most Hanami components (like hanami-validations or hanami-router) can be used standalone in any Ruby app. This is a good strategy if you want to adopt Hanami's patterns incrementally. Similarly, Sinatra's middleware can be used in Hanami.

Which framework has better documentation?

Sinatra's documentation is concise and easy to navigate. Hanami's documentation is more extensive but can be overwhelming for beginners. The community is helpful for both. For Hanami, the official guides and API docs are well-maintained, but examples are fewer than Sinatra's.

Should I migrate my Sinatra app to Hanami?

Only if you're experiencing pain from lack of structure. Migration is not trivial—you'll need to rewrite routes, actions, and views. It's often better to extract services into a separate Hanami app or rewrite the most complex parts first. Consider a strangler pattern: run both frameworks side by side and gradually move endpoints.

What about testing? Which is easier?

Sinatra is easier to start testing because you can write simple Rack tests. Hanami's testing setup requires more boilerplate but encourages better test isolation. If you value comprehensive unit tests, Hanami wins. If you prefer quick integration tests, Sinatra is simpler.

Recommendation Recap Without Hype

Choose Sinatra when: you're building a small API, a webhook, or a prototype with a short lifespan; your team is small and experienced enough to impose structure manually; you need the fastest possible boot time for serverless deployments. Choose Hanami when: you're building a multi-domain application that will evolve over years; your team values clean architecture and test isolation; you want a framework that enforces good practices without the weight of Rails.

If you're still unsure, start with Sinatra and commit to refactoring early. Set a rule: if the app exceeds 500 lines or 10 routes, extract into modules. If you find yourself fighting Sinatra's lack of structure, that's a signal to consider Hanami. Conversely, if you start with Hanami and feel it's slowing you down, switch to Sinatra for the prototype and migrate later. The worst choice is to not decide and let the codebase grow organically without a framework's guidance.

Your next steps: (1) Write a one-page description of your application's expected complexity and team size. (2) Build a small proof-of-concept in both frameworks—just the core feature. (3) Compare the resulting codebases: which one feels more maintainable? (4) Discuss with your team the trade-offs we've outlined. (5) Make a decision and commit to the framework's conventions. Remember, the best framework is the one that your team can use consistently and sustainably over the long term.

Share this article:

Comments (0)

No comments yet. Be the first to comment!