Hotwire(ホットワイヤー)は、画面の更新に使うデータをJSONではなく完成済みのHTMLとしてサーバーから送り、ページ遷移やフォーム送信をSPA並みの速さで見せるフロントエンドの手法です。名前は「HTML Over The Wire」の略で、Ruby on Railsの開発元である37signalsが、自社のメールサービスHEYを動かすために作り、2020年12月に公開しました。この記事では、Hotwireを構成するTurbo・Stimulus・Hotwire Nativeの役割分担と2026年10月時点の版、Rails 8.1.4で実際に生成されるファイルとStimulusコントローラの追加手順、Turbo Driveの通常のPOST送信で検証エラーに422を返す理由、ReactやHTMXとの使い分けを、公式ドキュメントとライブラリのソースで確認しながら整理します。
まとめ:Hotwireの要点
- Hotwireは単一のライブラリではなく、Turbo(通信と画面差し替え)・Stimulus(小さなJavaScript)・Hotwire Native(モバイルアプリの外枠)をまとめた呼び名。
- 2026年10月時点の最新版は、Turbo 8.0.23(2026年1月29日)、Stimulus 3.2.2(2023年8月7日)、Hotwire NativeはiOS 1.3.1・Android 1.3.2。
- Rails 7.0以降は
rails newの既定でturbo-railsとstimulus-railsが入る。Rails 8.1.4でも同じで、外すときは--skip-hotwireを付ける。コントローラはbin/rails generate stimulus 名前で足せば登録まで済む。 - Turbo Driveの通常のPOST送信に対し、検証エラーのHTMLを直接返す場合は422(Unprocessable Content)を使う。FramesやTurbo Streamsの応答とは区別する。
- 向くのはサーバー側で画面を組み立てる業務アプリや管理画面。オフライン動作や、ブラウザ内で状態を大量に持つエディタ型の画面には向かない。
英語の「hotwire」は、鍵を使わずに配線を直結して車のエンジンをかけることを指し、米国の旅行予約サイトHotwire.comも同じ綴りです。この記事で扱うのは、Web開発のHotwireです。
Hotwireの仕組み:JSONの代わりにHTMLを送る設計
ReactやVue.jsで組むSPAでは、サーバーはJSONを返し、ブラウザ側のJavaScriptがそのJSONからDOMを組み立てます。Hotwireはこの分担を逆にします。サーバーがテンプレートを描画してHTMLの断片を返し、ブラウザ側はそれを所定の場所に差し込むだけです。公式サイトは、この方式の利点を初回表示の速さと、テンプレートの描画をサーバーに残せることだと説明しています。
| 比較項目 | JSON+SPA(React等) | Hotwire |
|---|---|---|
| サーバーが返すもの | JSON | HTML(全体または断片) |
| 画面を組み立てる場所 | ブラウザ | サーバー(ERB等) |
| ルーティング | クライアント側にも持つ | サーバー側のみ |
| 状態の置き場所 | ブラウザのストア | データベースとHTML |
| 画面更新用JSON API | 構成に応じて設計 | 必須ではない |
公式サイトは「どのプログラミング言語でも」使える手法だと明記しており、Rails専用ではありません(Rails以外での使い方はFAQで補足します)。
役割の比重も公式が示しています。Stimulusの紹介文には、従来JavaScriptが必要だった操作の「少なくとも80%」はTurboが受け持ち、残りに少量のコードを足すのがStimulusだと書かれています。つまり、Hotwireで書くJavaScriptの大半は「Turboでは足りない部分の補修」です。
Turbo・Stimulus・Hotwire Nativeの役割分担と2026年10月時点の版
3つの構成要素は担当範囲がはっきり分かれています。版と公開日は、npmレジストリ・RubyGems・GitHubのリリース一覧から取得しました(2026年10月24日時点)。公開履歴:Turbo/Stimulus/Hotwire Native iOS/Hotwire Native Android/turbo-rails(RubyGems)
| 構成要素 | 担当 | 最新版(公開日) | Rails用gem |
|---|---|---|---|
| Turbo | 遷移・フォーム・部分更新 | 8.0.23(2026-01-29) | turbo-rails 2.0.23 |
| Stimulus | 小さなJavaScriptの整理 | 3.2.2(2023-08-07) | stimulus-rails 1.3.4 |
| Hotwire Native iOS | iOSアプリの外枠 | 1.3.1(2026-08-14) | 不要 |
| Hotwire Native Android | Androidアプリの外枠 | 1.3.2(2026-10-12) | 不要 |
Turbo 8系の現在地:8.0.0から2年でパッチ23本
Turbo 8.0.0は2024年2月7日に出ており、それ以降はメジャー・マイナーとも上がらず8.0.xのパッチだけが続いています。直近の8.0.23のリリースノートは「前のリリースの古くなった依存を更新してビルドし直した」という一文だけで、APIは変わっていません。turbo-rails gemは2系で番号が別ですが、2.0.23がnpmの@hotwired/turbo-rails 8.0.23と同じ日に出ており、npm版の依存は@hotwired/turbo ^8.0.23です。
Stimulus 3.2.2の公開時期と採用前の確認事項
Stimulusの最新リリースは2023年8月7日の3.2.2で、そこから3年以上新しい版が出ていません。GitHubのmainブランチには2026年7月25日にもコミットがありますが、中身はDependabotによる依存パッケージの版上げ(pbkdf2・got等)と、ハンドブックのリンク削除でした。コントローラ・ターゲット・値・アクションというAPIが3.0(2021年9月)でほぼ固まり、3.2.0(2022年11月)ではOutlets APIが追加され、3.2.2でもPageUp・PageDownのキーマッピングや数値内のアンダースコア対応が追加されています。公開版の更新間隔だけでは、リリースが行われない理由や保守上の懸念の有無は判断できません。採用時は、公開版とmainブランチの差分、未解決の不具合、自社の対象ブラウザでの動作を確認してください。
Hotwire Nativeの版番号は公式サイトより GitHub が先行
Hotwire Nativeの公式サイト(native.hotwired.dev)は、2026年10月24日時点で「Current iOS version: 1.3.0 — released Jul 7, 2026」「Current Android version: 1.3.1 — released Jul 27, 2026」と表示しています。一方、GitHubにはiOSの1.3.1(2026年8月14日)とAndroidの1.3.2(2026年10月12日)が公開済みです。Androidの1.3.2は、スクリーンショットを正しいウィンドウから取得しシステムメモリの状況に応じて取得を制限する修正と、入れ子のNavigatorHostが別のインスタンスを置き換えるときにナビゲーショングラフを読み込む修正の2件だけで、APIの変更はありません。導入時に指定する版は、公式サイトの表示ではなくGitHubのリリース一覧で確認してください。
Turboの4つの仕組み:Drive・Frames・Streams・ページリフレッシュ
Turboは、リンクとフォームの扱いを横取りして、ページ全体を読み込み直さずに画面を差し替えるライブラリです。ここでは4つの仕組みを紹介します。Driveとページリフレッシュはページ単位、Framesは特定の領域、Streamsは指定した要素や複数箇所の更新を担います。各機能の詳しい動作はTurboによるRailsの画面更新の実装で、部分更新の実装はturbo_frame_tagの使い方とContent missingの対処で扱っています。
Turbo Drive:fetchによるページ遷移とフォーム送信
Turboを読み込むだけで有効になります。リンクのクリックやフォーム送信をfetchで行い、返ってきたHTMLの<body>を差し替え、<head>はマージします。CSSとJavaScriptを毎回読み直さないぶん、画面の切り替えが速く見えます。書き換えるコードはゼロです。副作用として、DOMContentLoadedは最初の1回しか発火しません。画面遷移ごとに走らせたい初期化処理はturbo:loadイベントで受けるか、後述のStimulusコントローラに移します。
Turbo Frames:同じidを持つ領域の部分更新
<turbo-frame id="...">で囲んだ領域の中のリンクとフォームは、応答HTMLの中から同じidのフレームを探し、その部分だけを差し替えます。応答に同じidのフレームが無いと、フレームの中に「Content missing」と表示され、コンソールには「did not contain the expected <turbo-frame id=…>」という警告が出ます(Turbo 8.0.23のソースで確認)。インライン編集が動かないときは、まず応答側のフレームidを疑ってください。
<%= turbo_frame_tag dom_id(@comment) do %>
<p><%= @comment.body %></p>
<%= link_to "編集", edit_comment_path(@comment) %>
<% end %>
編集画面(edit.html.erb)側も同じturbo_frame_tag dom_id(@comment)でフォームを囲むと、「編集」を押したときに一覧の中のその行だけがフォームに入れ替わります。
Turbo Streams:1回の応答による複数箇所の更新
フレームは1か所しか更新できません。フォームを1回送信して「一覧に1件追加し、件数表示も変え、フォームを空に戻す」といった複数箇所の更新をするときは、Turbo Streamsを使います。<turbo-stream>要素のaction属性で操作を指定し、<template>の中身をtargetで指定したidの要素に適用します。
<turbo-stream action="append" target="comments">
<template>
<p id="comment_42">新しいコメント</p>
</template>
</turbo-stream>
Turbo 8.0.23に組み込まれているアクションは、append・prepend・replace・update・remove・before・after・refreshの8つです(パッケージが公開しているStreamActionsのキーを実行して確認)。replaceとupdateにはmethod="morph"を付けられ、要素を丸ごと入れ替えずに差分だけを反映できます。HTTP応答として返す場合はContent-Typeをtext/vnd.turbo-stream.htmlにします。Action Cable(WebSocket)経由でサーバーから押し出すこともでき、チャットや通知のようなリアルタイム更新はこの経路で作ります。WebSocket自体の仕組みはWebSocketの仕組みとNode.js実装を参照してください。
ページリフレッシュとモーフィング:Turbo 8で加わった更新方法
Turbo 8で加わった仕組みです。<head>に<meta name="turbo-refresh-method" content="morph">を置くと、同じページへの再読み込み(ページリフレッシュ)のときに<body>を丸ごと入れ替えず、変わった要素だけを書き換えます。既定値はreplaceです。スクロール位置も保ちたい場合はturbo-refresh-scrollにpreserveを指定します。
Railsではturbo-railsのbroadcasts_refreshesと組み合わせると、どの要素をどう更新するかを1つずつ書かずに済みます。モデルが変わったら「再読み込みせよ」という合図だけを配信し、受け取った画面が自分でリフレッシュする方式です。下の例は既存Boardの更新・削除を購読します。Cardの変更も反映する場合は、Card側にbelongs_to :board, touch: trueなどを設定し、Boardの更新を発生させます。
# app/models/board.rb
class Board < ApplicationRecord
has_many :cards
broadcasts_refreshes
end
<%# app/views/boards/show.html.erb %>
<%= turbo_stream_from @board %>
個別のappendやreplaceを並べる方式は、画面の種類が増えるたびにストリームのテンプレートも増えます。複数人が同じ画面を見る看板・ダッシュボード型の画面なら、先にリフレッシュ方式を試し、ページHTMLの再取得による転送量やサーバーの描画負荷が問題になった箇所だけ個別のアクションに切り替えるほうが、書く量を抑えられます。
Stimulusの書き方:コントローラ・ターゲット・値・アクション
Stimulusは、HTMLに書いたdata-属性を手がかりに、JavaScriptのクラス(コントローラ)を要素へ結び付けるフレームワークです。DOMを自前で生成せず、サーバーが返したHTMLに振る舞いを足すことだけを担います。次は、テキストエリアの入力長をUTF-16コード単位で数え、上限を超えると出力要素にoverクラスを付けるコントローラです。絵文字などは見た目の1文字とカウントが一致しません。表示を変えるには、overクラスのCSSを別途定義します。
// app/javascript/controllers/counter_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["input", "output"]
static values = { max: Number }
connect() {
this.update()
}
update() {
const length = this.inputTarget.value.length
this.outputTarget.textContent = length
this.outputTarget.classList.toggle("over", length > this.maxValue)
}
}
<div data-controller="counter" data-counter-max-value="140">
<textarea data-counter-target="input"
data-action="input->counter#update"></textarea>
<p><span data-counter-target="output">0</span> / 140</p>
</div>
このコードは、Node.js 26.5とjsdom上で@hotwired/stimulus 3.2.2に登録して動かし、上限を10にして13文字を入力すると、出力が「13」になりoverクラスが付くこと、最初から6文字入っているテキストエリアではconnect()の時点で「6」と表示されることを確認しています。
Stimulusの主なAPIは次の6つです。実務でまず覚えるのは上の3つで、残りは必要になってからで足ります。
- controllers:
data-controller="counter"で要素とクラスを結び付ける。Railsでの登録方法は後述の「Stimulusコントローラを追加する手順」で扱う。 - actions:
data-action="input->counter#update"の形で「イベント名->コントローラ名#メソッド名」を指定する。 - targets:
static targetsに並べた名前で、this.inputTargetのように要素を参照できる。 - values:
data-counter-max-valueを型付きで読む。変更時にmaxValueChanged()が呼ばれる。 - classes:付け外しするCSSクラス名をHTML側から渡す。
- outlets:別のコントローラを参照する。3.2.0で加わった。
Turbo Driveで画面が差し替わっても、Stimulusはdata-controllerを持つ要素の出現と消滅を監視しているため、connect()とdisconnect()が自動で呼ばれます。前の章で触れたDOMContentLoadedの問題は、初期化処理をconnect()へ移せば起きません。
Rails 8.1での導入と最小構成
rails newの既定で入るgemと外し方
Rails 8.1.4(2026年9月24日公開)のアプリジェネレータ(railtiesのapp_base.rb)は、--skip-hotwireが無ければGemfileにturbo-railsとstimulus-railsを書き込み、importmap:installの後にturbo:install stimulus:installを実行します。JavaScriptの読み込み方式の既定はimportmapで、Node.jsもバンドラも要りません。Ruby 4.0.6でrails _8.1.4_ newを実行すると、Gemfile.lockはturbo-rails 2.0.23・stimulus-rails 1.3.4・importmap-rails 2.2.3・rack 3.2.7で固定され、config/importmap.rbとapp/javascript/application.jsは次の内容になりました。
# config/importmap.rb
pin "application"
pin "@hotwired/turbo-rails", to: "turbo.min.js"
pin "@hotwired/stimulus", to: "stimulus.min.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
pin_all_from "app/javascript/controllers", under: "controllers"
// app/javascript/application.js
import "@hotwired/turbo-rails"
import "controllers"
Turboはimport "@hotwired/turbo-rails"の1行で全ページに効きます。import "controllers"が読み込むapp/javascript/controllers/index.jsは、eagerLoadControllersFrom("controllers", application)でpin_all_fromした全コントローラを登録します。
# 新規アプリ(Turbo・Stimulus・importmapが入る)
rails new myapp
# Hotwireを入れない
rails new myapp --skip-hotwire
# 既存アプリへ後から入れる
# 前提:importmap-railsまたはjsbundling-railsの導入・設定が完了していること
bundle add turbo-rails stimulus-rails
bin/rails turbo:install stimulus:install
Rails以外の環境では、npm install @hotwired/turbo @hotwired/stimulusで入れ、エントリーポイントでimport "@hotwired/turbo"と書くだけでTurbo Driveが動き始めます(パッケージの末尾でstart()が呼ばれる)。
Stimulusコントローラを追加する手順:generate stimulusとimportmap
コントローラのファイルは手で作ってもかまいませんが、stimulus-railsのジェネレータを使うと命名の取り違えが起きません。Rails 8.1.4のアプリで実行すると、次のファイルが1つだけ作られます。
$ bin/rails generate stimulus counter
create app/javascript/controllers/counter_controller.js
import { Controller } from "@hotwired/stimulus"
// Connects to data-controller="counter"
export default class extends Controller {
connect() {
}
}
importmap構成では、これ以外の作業はありません。bin/importmap jsonの出力に"controllers/counter_controller"が加わり、HTML側でdata-controller="counter"を書けば生成したコントローラが接続されます。前章の文字数カウンターとして動かすには、生成された空のクラスを前章の実装に置き換え、ターゲット・値・アクションを含むHTMLも配置します。名前に_や/を含めると、data属性では-と--に置き換わります(admin/user_listならdata-controller="admin--user-list")。
jsbundling-rails(esbuild・Bun等)を使う構成では、コントローラの登録がcontrollers/index.jsへの明示的なregisterになります。ジェネレータはconfig/importmap.rbが無いときだけbin/rails stimulus:manifest:updateを自動で実行してindex.jsを書き直します(stimulus-rails 1.3.4のジェネレータのソースで確認)。手でファイルを足した場合は、このコマンドで登録一覧を更新するか、index.jsにimportとapplication.registerを手動で追加します。
開発中の再読み込みには、37signalsのHotwire Spark(hotwire-spark gem、最新0.1.13・2025年1月25日)が使えます。rails newの既定には入らないので、Gemfileのgroup :developmentにgem "hotwire-spark"を足します。READMEによると、importmap構成ではHTMLの変更をモーフィングで反映し、Stimulusコントローラは変更されたファイルを取得し直してページ内の全コントローラを再読み込みします。バンドラ構成ではHTMLやコントローラの変更時にTurboの画面遷移でページを読み直します。
フォームのステータスコード:422と303を返す理由
Turbo Driveの導入時には、「バリデーションエラーのときにフォームが再表示されない」という症状に注意が必要です。原因はステータスコードです。Turboのハンドブックは、状態を変更するフォーム送信で通常のHTML応答を返す場合、成功時に303リダイレクトを期待し、検証エラーなどでは4xx・5xxのHTMLを直接描画できると説明しています。POSTの結果を表示した画面を再読み込みすると、ブラウザが再送信の確認を出すためです(Turbo Streamsで応答する場合は別の扱いになります)。Turbo Driveによる通常のPOST送信に、リダイレクトせず200のHTMLを直接返すと、Turbo 8.0.23は「Form responses must redirect to another location」というエラーを出して何も描画しません。
次は、body属性を持つCommentモデル、commentsのルーティング、new・showのビューを用意したアプリから、createとdestroyを抜き出した例です。
class CommentsController < ApplicationController
def create
@comment = Comment.new(comment_params)
if @comment.save
redirect_to @comment, notice: "投稿しました", status: :see_other
else
render :new, status: :unprocessable_content
end
end
def destroy
Comment.find(params[:id]).destroy!
redirect_to comments_path, status: :see_other
end
private
def comment_params
params.expect(comment: [:body])
end
end
Rails 8.1.4のscaffoldテンプレートも同じ形で、失敗時は422、updateとdestroyのリダイレクトには:see_other(303)を付けています。422を表すシンボルは、Rack 3.1以上なら:unprocessable_content、3.1未満なら:unprocessable_entityです(RailsのActionDispatch::ConstantsがRackの版で切り替えている)。古い記事のコードを写すときは、Gemfile.lockのRackの版と合っているか確認してください。
Hotwire Nativeによるモバイルアプリ開発
Hotwire Nativeは、Webの画面をiOS・Androidアプリの中に表示し、画面遷移やナビゲーションバーだけをネイティブで作るフレームワークです。2024年9月25日に37signalsが発表しました。以前は画面表示を担うTurbo Nativeと、ネイティブ部品との橋渡しを担うStradaに分かれていましたが、発表記事によると「Turbo+Stimulus+Stradaの関係がわかりにくい」という声が続いたため、この2つを1つにまとめて改名しています。Turbo Nativeという名前で書かれた資料は、Hotwire Nativeの旧称のものと読み替えてください。
公式ドキュメントは、仕組み・基本のナビゲーション・Path Configuration(URLごとの表示方法の設定)・Bridge Components(Web側から呼べるネイティブ部品)・Native Screens(完全ネイティブの画面)の順に構成されています。Web側で完結する画面の変更を、アプリ本体の再配布なしで反映できる利点があります。ネイティブ側の変更には、アプリ本体の更新が必要です。逆に、カメラ・位置情報・プッシュ通知の細かな制御のように端末機能に深く触れる画面は、Bridge ComponentsかNative Screensでネイティブのコードを書くことになります。Web側の橋渡しに使うnpmパッケージは@hotwired/hotwire-native-bridge(最新1.2.2)です。
Hotwire Nativeが前提にするのは「画面の大半がWebで足りる」アプリです。オフラインで使う画面や、端末機能を使う画面が大半を占めるなら、Web画面を包む方式の利点が薄れます。その場合は、Flutter・React Nativeによるクロスプラットフォーム開発のように、UIそのものをアプリ側で組む方式と比べて選びます。
ReactやHTMXとの比較と採用判断
Hotwireとの比較対象には、UIライブラリのReactを使ったSPA構成や、同じHTML返却型のHTMXがあります。HTMXの実装はhtmxの使い方:hx-属性の実装手順で扱っています。
| 観点 | Hotwire | HTMX | React+API |
|---|---|---|---|
| サーバーが返すもの | HTML | HTML | JSON |
| ページ遷移の高速化 | 既定で有効 | hx-boostで指定 | ルーターで実装 |
| 書き方 | data属性+Stimulus | hx-属性 | JSX |
| リアルタイム配信 | Turbo Streams | 拡張機能 | 自前実装 |
| モバイルアプリ | Hotwire Native | 公式なし | React Native |
| Rails統合 | 既定で同梱 | gemは有志 | API分離 |
Hotwireを選ぶべき条件
サーバー側で画面を組み立てるRailsアプリで、画面の大半がフォーム・一覧・詳細の組み合わせなら、Hotwireが第一候補です。フロントエンド専任者がいなくても、ERBとコントローラの延長で画面の部分更新まで書けます。Railsの生みの親であるDHHが、SPA偏重への対案としてこの方式を押し出してきた経緯はDHHの経歴と設計思想にまとめています。
Hotwireを採用しない場面
次の条件に当てはまる画面では、Hotwireを主軸にしないでください。
- オフラインで動く必要がある:新しい画面の取得やサーバーへの保存には通信が必要です。表示済みの画面や履歴キャッシュは利用できる場合がありますが、本格的なオフライン編集・同期には別途設計が必要です。
- ブラウザ側で大量の状態を持つ:図形エディタ、表計算、ドラッグ操作の多いカンバンなど。操作のたびにサーバーへ往復すると遅延が体感できる。
- Web画面もJSON APIとクライアント側の状態管理で揃える方針:ネイティブアプリや外部連携向けのJSON APIを、Web画面からも同じように使う構成に統一するなら、SPA構成を優先します。APIが必要というだけなら、Hotwireを除外する理由にはなりません。API側の構成はRails APIの作成手順とReact連携を参照。
一部の画面だけがこれに当たるなら、アプリ全体をSPAにする必要はありません。その画面だけをReactなどで作り、残りをHotwireで作る構成も取れます。Stimulusコントローラのconnect()でReactのコンポーネントをマウントし、disconnect()でアンマウントすれば、Turbo Driveの画面遷移で要素が差し替わっても後始末が漏れません。
Hotwireに関するよくある質問
Hotwireは何の略ですか?日本語ではどういう意味ですか?
Web開発のHotwireは「HTML Over The Wire」の略で、「通信路(wire)に乗せてHTMLを送る」という意味です。読み方はホットワイヤーです。英単語の「hotwire」は配線を直結して車のエンジンをかけることを指し、米国の旅行予約サイトHotwire.comとも無関係です。
HotwireはRails以外(DjangoやLaravel)でも使えますか?
使えます。TurboとStimulusはnpmパッケージ(@hotwired/turboと@hotwired/stimulus)として配布されており、HTMLを返すサーバーであれば言語を問いません。Railsではturbo-railsがビューのヘルパーやストリーム配信を提供します。Rails以外にも、Symfony UX Turboのようにテンプレート部品と配信機能を備える統合があります。ほかのフレームワークでは、コミュニティ製のライブラリを使うか、<turbo-stream>のHTMLを自分で組み立てることになります。
HotwireとReactやVue.jsの違いは何ですか?
JSON APIを使うクライアント描画型のReact・Vue.js構成では、ブラウザ側で画面を組み立てます。Hotwireはサーバーで生成したHTMLを受け取って更新しますが、ReactやVue.jsにもサーバー描画の構成があります。HotwireではAPIとクライアント側のルーティングが要らない代わりに、オフライン動作や、ブラウザ内で大量の状態を持つ画面は苦手です。比較表と採用しない場面は本文の「ReactやHTMXとの比較と採用判断」にまとめています。
TurboとStimulusの違いは何ですか?
Turboはサーバーとの通信と画面の差し替えを担い、JavaScriptを書かずに動きます。StimulusはTurboでは足りない小さな振る舞い(文字数カウント、開閉、クリップボードへのコピー等)を、HTMLのdata属性とJavaScriptのクラスで書くための仕組みです。まずTurboで書けないかを考え、足りない部分だけをStimulusで書くのが基本の順番です。
Hotwireでスマホアプリは作れますか?
Hotwire Nativeを使えば、iOSとAndroidのアプリを作れます。Webの画面をアプリ内に表示し、ナビゲーションや一部の部品だけをネイティブで作る方式なので、既存のRailsアプリの画面をそのまま使い回せます。以前のTurbo NativeとStradaは、2024年9月にHotwire Nativeへ統合されました。