Introduction

Two pieces of news landed close together in the Ruby world, and they’re related.

First, three long-running projects — Hanami, dry and rom — have come together under one name: Hanakai. Second, the first release under that banner shipped: Hanami 3.0, fittingly titled “in full bloom”.

If you followed the Hanami 2.0 to 2.2 story, this is where it goes next.

What Hanakai is

Hanakai isn’t a new framework or a rewrite. It’s the three projects — which the announcement notes have “lived alongside each other across a decade and billions of downloads” — deciding to share a single community, website and identity. The name means “flower fellowship” in Japanese, keeping Hanami’s nature theme.

Concretely, for anyone using these gems:

  • The gem names don’t change. hanami, the dry-* gems and the rom-* gems stay exactly as they are, now maintained by one larger team.
  • The docs consolidate at hanakai.org/learn, as community-editable Markdown, instead of being scattered across separate sites.
  • Nothing you built breaks because of the merger itself. It’s an organisational change, not a technical one.

My read: this is good news for the explicit, functional corner of Ruby. Hanami, dry and rom always shared a philosophy and a lot of contributors; having one front door and one community around them means less fragmentation and an easier story to tell newcomers.

Hanami 3.0: in full bloom

The first release under Hanakai is a substantial one.

Mailers

Hanami now ships mailers that sit alongside actions, views and operations, with the same declarative style:

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

      expose :user
    end
  end
end

Internationalization

i18n is built in. Translations live in a config file:

# config/i18n/en.yml
en:
  posts:
    index:
      title: "Latest posts"
  greetings:
    welcome: "Welcome, %{name}!"

Views and actions get a t helper with lazy lookup keyed to the current template or action:

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

And anywhere else you can inject it as a dependency:

class Greeter
  include Deps["i18n"]

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

Localization comes along too:

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

Minitest support

RSpec is still the default, but Hanami 3.0 offers an equally complete Minitest setup. You choose at generation time:

hanami new my_app --test=minitest

Performance

This is the headline the numbers back up. The release reports test requests “nearly 3x faster over HTTP” using a fraction of the memory, and “14x fewer allocations per request” for an action resolving nine components. A minimal action drops from 88 allocations to 17 and runs 3.7x faster; view rendering goes from 100 allocations to 42, 2.9x faster. Under the hood, action config is snapshotted up front instead of being recomputed per request, and component memoization is on by default.

Breaking changes worth knowing

Upgrading from 2.x isn’t free. The notable changes:

  • hanami-controller is renamed to hanami-action.
  • hanami-validations has been retired (dry-validation covers this ground directly).
  • Hanami 3.0 requires Ruby 3.3 or newer.
  • View exposures are undecorated by default; opt back in per exposure with .decorate().
  • The router’s plain redirect now requires an explicit code: argument.

My take

Back at 2.2, Hanami had just completed its full-stack story with the ROM-based database layer. 3.0 rounds it out with the last everyday pieces most apps need, mailers and i18n, and makes the whole thing markedly faster at the same time.

Wrapping it in Hanakai is the part I find most encouraging, though. The technical direction was never the problem for Hanami, dry and rom; visibility and a shared community were. One name, one site, one place to learn all three gives this whole approach a much better shot at reaching the people it would suit. If a database-backed, explicit, dry-flavoured stack appeals to you, this is a good moment to look again.

Have comments or want to discuss this topic?

Send an email to ~bounga/public-inbox@lists.sr.ht