Gemfile
gem "turbo-rails"
gem "stimulus-rails"
gem "importmap-rails"
Rails Frontend
Hotwire keeps Rails in charge of HTML while Turbo handles navigation and page updates, and Stimulus adds focused JavaScript where the browser needs behavior.
Setup
Gemfile
gem "turbo-rails"
gem "stimulus-rails"
gem "importmap-rails"
config/importmap.rb
pin "@hotwired/turbo-rails", to: "turbo.min.js"
pin "@hotwired/stimulus", to: "stimulus.min.js"
pin_all_from "app/javascript/controllers", under: "controllers"
app/javascript/application.js
import "@hotwired/turbo-rails"
import "controllers"
app/javascript/controllers/index.js
import { application } from "controllers/application"
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
eagerLoadControllersFrom("controllers", application)
When to Use Each Part
Use it when the HTML already belongs to Rails.
Best forUse for normal page navigation and form submissions where server-rendered HTML should feel faster.
SetupImport `@hotwired/turbo-rails`; Rails enables it for links and forms by default.
Use cautionDisable per element with `data-turbo="false"` when a third-party widget or redirect flow needs full browser behavior.
Use it when the HTML already belongs to Rails.
Best forUse when one region owns its own navigation, such as inline edit forms, paginated panels, modal bodies, or lazy-loaded sections.
SetupWrap the region in `turbo_frame_tag "frame_id"`; responses must include a matching frame.
Use cautionDo not add frames only because a Turbo Stream needs a target. A normal element with an id is enough for streams.
Use it when the HTML already belongs to Rails.
Best forUse after create, update, and destroy actions when Rails should append, replace, remove, or refresh pieces of the page.
SetupRespond to `format.turbo_stream` in the controller or render a `.turbo_stream.erb` template.
Use cautionReturn HTML redirects for workflows where the user should land on a different page.
Use it when the HTML already belongs to Rails.
Best forUse for real-time updates from other users or background work, such as chats, notifications, dashboards, and job progress.
SetupUse `turbo_stream_from` in the view and model broadcasts or Action Cable broadcasts on the server.
Use cautionSkip the socket when the update only needs to answer the current user's form submission.
Use it when the HTML already belongs to Rails.
Best forUse for behavior that belongs in the browser: toggles, clipboard buttons, previews, keyboard shortcuts, validation hints, and small widgets.
SetupGenerate controllers in `app/javascript/controllers` and connect them with `data-controller`, `data-action`, and targets.
Use cautionDo not move business rules into Stimulus; keep durable decisions in Rails and use Stimulus to enhance the UI.
Examples
<%= turbo_frame_tag "profile_card" do %>
<%= link_to "Edit", edit_profile_path %>
<% end %>
respond_to do |format|
format.turbo_stream { render turbo_stream: turbo_stream.append("messages", @message) }
format.html { redirect_to messages_path }
end
<div data-controller="clipboard">
<button data-action="clipboard#copy">Copy</button>
</div>
<%= turbo_stream_from "room_1" %>
<div id="messages"></div>
Official references