Hanami 3.0: In Full Bloom

PuercoPop1 pts0 comments

Hanami 3.0: In full bloom<br>&middot; Hanakai

On this page

From the very beginning we set out to make Hanami a different kind of Ruby framework: clear, modular, and built to grow. Today it comes into full bloom. We’re thrilled to share Hanami 3.0 with you!

This release rounds out the framework with three big new features: mailers , internationalization , and Minitest . On top of that, your apps are now faster by default , and your developer experience is sharper, from your logs all the way to your assets.

First-class mailers

Our long lost gem is back! Hanami apps now come with integrated mailers, which feel right at home next to your actions, views, and operations.

Mailer classes describe everything you need to deliver an email:

module Bookshelf<br>module Mailers<br>class Welcome Bookshelf::Mailer<br>from "welcome@bookshelf.test"<br>to { |user:| user.email }<br>subject { |user:| "Welcome to Bookshelf, #{user.name}!" }

expose :user<br>end<br>end<br>end

As standalone objects, mailers are injectable via the Deps mixin and accessible wherever you need them. Call .deliver and the mailer will use your input to prepare headers and render mail body templates, which work as a fully featured extension of your view layer.

Mailers support multiple delivery methods. SMTP delivery works out of the box: populate some env vars for your SMTP host and you’re good to go. In test, your emails are accumulated in memory for you to inspect.

If you need something more, you can also write your own delivery methods. In addition to a clean interface for these, Hanami Mailer provides hooks for threading delivery options all the way through your mailers, allowing new delivery methods to make the most of special features offered by email delivery providers.

Like all our gems, Hanami Mailer is also designed for standalone use. Check out the comprehensive README for everything you need to know about using it in your Ruby app.

Hanami Mailer leans on the venerable mail gem to handle all its low-level mail wrangling. Thank you to the mail maintainers for all their work over the years!

Built-in internationalization

Taking your apps to the world just got easier: i18n is now built right into Hanami. Bundle the i18n gem and Hanami sets up a self-contained translation backend in your app and every slice, with translate and localize helpers ready to use across your actions and views.

Your translations live in config/i18n/ in your app or slice:

# config/i18n/en.yml<br>en:<br>posts:<br>index:<br>title: "Latest posts"<br>create:<br>created: "Your post is live!"<br>greetings:<br>welcome: "Welcome, %{name}!"

From there, i18n helpers are everywhere you’d expect them! Like in your views:

app/templates/posts/index.html.erb %><br>h1> t(".title") %>h1>

And your actions:

# app/actions/posts/create.rb<br>def handle(request, response)<br>response.flash[:notice] = t(".created")<br># ...<br>end

And for everywhere else, the "i18n" component is just one Deps mixin away:

class Greeter<br>include Deps["i18n"]

def call(name)<br>i18n.t("greetings.welcome", name:)<br>end<br>end

We’ve got localization too. localize formats your dates and times for the current locale, and ships with sensible defaults for English:

localize(Date.new(2026, 5, 22))<br># => "Fri, 22 May 2026"

localize(Time.new(2026, 5, 22, 9, 5), format: :short)<br># => "22 May 9:05 am"

Like every aspect of Hanami, i18n is designed to work out of the box with minimal setup, but there are plenty of settings if you need something custom. Check out the i18n guide for the full picture.

You can’t spell internationalization without the i18n gem, which does all the heavy lifting for this new feature. So a big en-AU “cheers, mates” to the i18n maintainers — thank you for helping Rubyists the world over!

Now with Minitest

Hanami has always shipped with a ready-to-go RSpec setup. We’re delighted we can finally make the other half of you happy, thanks to our brand new Minitest support!

Pick your testing framework when you generate an app:

$ hanami new my_app --test=minitest

RSpec stays our default, but reach for Minitest and you’ll now get an equally complete setup, rather than having to build something yourself.

A big thank you to Ryan Davis and all the contributors for their work on Minitest. Minitest ships with Ruby itself, and we’re glad to make it part of the Hanami story going forward.

Faster by default

Hanami 3.0 is significantly faster, and you can enjoy the benefits right from the get-go. In a test app, the same request runs nearly 3x faster over HTTP while allocating a fraction of the memory.

Hanami now memoizes your components by default . This means that each component in your app’s containers is resolved just once and then reused, rather than built fresh every time it’s needed.

This is the change you’ll really feel. We took an app whose action resolves a graph of nine components and renders a view, then measured the same request on 2.3 and 3.0. In 3.0, there were 14x fewer allocations per request and nearly 3x the throughput over HTTP (and closer to...

hanami i18n mailers minitest mailer welcome

Related Articles