Rails domina el ecosistema Ruby para aplicaciones web. Es maduro, tiene una comunidad enorme y el stack que incluye en 2024-2026 (Solid Queue, Hotwire, Kamal) cubre la mayoría de las necesidades. Pero no es la única opción, y hay casos donde sus alternativas tienen ventajas reales. Hanami 2 y Roda son las dos más serias para proyectos que buscan algo diferente.
El argumento contra Rails
Rails sigue el principio de «convention over configuration» con mucha agresividad. Eso es una ventaja cuando trabajas dentro de sus convenciones, pero puede convertirse en obstáculo cuando necesitas salirte de ellas. Rails tiene mucha magia: métodos que aparecen automáticamente, callbacks que se ejecutan sin que los llames explícitamente, un sistema de carga de clases que puede sorprender.
Para APIs de alto rendimiento, la carga de Rails (ActiveRecord, ActionView, todos sus railtie) puede ser excesiva. Para proyectos grandes con equipos que priorizan la explicitad sobre la convención, el modelo de Rails puede no encajar.
Hanami 2: arquitectura explícita
Hanami 2.0 salió en noviembre de 2022 después de una reescritura casi completa respecto a la versión 1. El foco es la separación de responsabilidades y la inyección de dependencias explícita.
# Estructura de un proyecto Hanami 2
mi_app/
app/
actions/ # Acciones HTTP (equivalente a controladores Rails)
repos/ # Repositorios de datos
views/ # Vistas
entities/ # Objetos de dominio
config/
app.rb # Configuración principal
providers/ # Proveedores de servicios (DB, mailer, etc.)
slices/ # Partes independientes de la app (como engines en Rails)
La inyección de dependencias es automática a través del contenedor de la aplicación:
# app/actions/usuarios/crear.rb
module MiApp
module Actions
module Usuarios
class Crear < MiApp::Action
include Deps[
"repos.usuario_repo",
"servicios.email_verificacion"
]
params do
required(:nombre).filled(:string)
required(:email).filled(:string)
end
def handle(request, response)
halt 422, response.render unless request.params.valid?
usuario = usuario_repo.crear(request.params[:usuario])
email_verificacion.enviar(usuario)
response.status = 201
response.body = usuario.to_json
end
end
end
end
end
Cada acción es una clase con un método handle. Las dependencias se declaran explícitamente con include Deps[...]. No hay magia: si necesitas el repositorio de usuarios, lo declaras y el contenedor lo inyecta.
Persistencia con ROM (Ruby Object Mapper)
Hanami usa ROM como capa de persistencia en lugar de ActiveRecord. ROM separa las queries de los objetos de dominio:
# app/repos/usuario_repo.rb
class UsuarioRepo < MiApp::DB::Repo
commands :create, :update, :delete
def por_email(email)
usuarios.where(email: email).one
end
def activos
usuarios.where(activo: true).to_a
end
private
def usuarios
root
end
end
La diferencia con ActiveRecord: el modelo (entidad) no sabe nada de la base de datos, y el repositorio se encarga de las queries. Es más verboso pero más fácil de testar en aislamiento.
Roda: el micro-framework de la familia
Roda es algo distinto: un micro-framework de routing basado en el árbol de rutas. Es extremadamente rápido y minimalista. Fue creado por Jeremy Evans (también autor de Sequel, el ORM alternativo a ActiveRecord).
# config.ru
require 'roda'
class MiApp < Roda
plugin :json
plugin :halt
route do |r|
r.root do
{ mensaje: 'Hola desde Roda' }
end
r.on 'usuarios' do
r.is do
r.get do
# GET /usuarios
Usuario.all.map(&:to_hash)
end
r.post do
# POST /usuarios
datos = JSON.parse(r.body.read)
usuario = Usuario.create(datos)
response.status = 201
usuario.to_hash
end
end
r.on :id do |id|
usuario = Usuario.find(id: id.to_i)
r.halt(404, { error: 'No encontrado' }) unless usuario
r.is do
r.get { usuario.to_hash } # GET /usuarios/:id
r.delete { usuario.destroy; '' } # DELETE /usuarios/:id
end
end
end
end
end
run MiApp
El routing «en árbol» de Roda significa que las rutas se definen como un árbol de decisiones. Cuando coincide un segmento de la ruta, entra en ese bloque y sigue hacia abajo. Es más eficiente que el routing lineal de Sinatra y más explícito que Rails.
Roda con Sequel: el stack ligero
Roda y Sequel forman un stack muy usado para APIs de alto rendimiento:
# Gemfile
gem 'roda'
gem 'sequel'
gem 'pg'
# config/database.rb
require 'sequel'
DB = Sequel.connect(ENV['DATABASE_URL'])
# models/usuario.rb
class Usuario < Sequel::Model
plugin :json_serializer
plugin :validation_helpers
def validate
super
validates_presence [:nombre, :email]
validates_unique :email
end
end
Sequel tiene un DSL de queries muy expresivo, sin la magia de ActiveRecord pero con más control sobre el SQL generado.
Cuándo tiene sentido cada uno
Framework | Mejor para | Curva de aprendizaje |
Rails 8 | Apps completas, equipos con experiencia Rails, prototipado rápido | Media (mucho aprendido por convención) |
Hanami 2 | Apps grandes con DDD, equipos que priorizan explicitad, microservicios | Alta (hay que aprender ROM, el contenedor, slices) |
Roda | APIs de alto rendimiento, micro-servicios, casos donde Rails es excesivo | Baja (es muy simple, pero minimalista) |
El estado actual en 2026
Hanami 2 sigue madurando. La comunidad es pequeña comparada con Rails, pero activa. La documentación ha mejorado mucho desde el lanzamiento de 2.0. La versión 2.2 (2024) añadió soporte para Assets y mejoró la integración con Hanami::View.
Roda es quizás el framework Ruby más infrautilizado. Jeremy Evans lo usa como base para muchos de sus proyectos personales y es el framework detrás de varias aplicaciones de producción de alto tráfico. Si necesitas un punto de comparación con el mundo Python, el artículo sobre FastAPI en 2026 muestra cómo el ecosistema Python resuelve el mismo problema de APIs ligeras con rendimiento alto.
Para la mayoría de los proyectos nuevos en Ruby, Rails 8 sigue siendo la primera opción. Pero conocer Hanami y Roda da perspectiva sobre qué decisiones de diseño tomó Rails y cuáles son sus trade-offs. Eso solo mejora el código que escribes con Rails.
Imagen: Pexels / Digital Buggu
