Skip to content

Lesson 1 — The Hotwire mental model

A brief history

When Hotwire launched with Rails 7, the recommended approach to interactivity was Turbo Frames and Turbo Streams. Frames let you scope updates to a region of the page. Streams let you send targeted DOM operations from the server. Together they covered most interactive UI needs — but they required explicit wiring: matching frame IDs, separate format.turbo_stream blocks, and careful coordination between templates.

In practice this was more work than it looked. Building a calendar in HEY, the Basecamp team hit the ceiling — too many frames, too many stream actions, an explosion of partial updates to coordinate. They looked for a better approach and found it in DOM morphing.

Turbo 8, released in early 2024, introduced page refresh with morphing. The idea is simple: after a form submission or action, the server re-renders the full page and redirects back. Instead of replacing the entire <body> as Turbo Drive did, Turbo 8 diffs the new HTML against the current DOM using the idiomorph library and applies only the changes — morphing in place, preserving scroll position and ephemeral state.

The result is that the default Rails programming model — render a full page, redirect after POST — now produces a genuinely smooth UI without any explicit Turbo wiring.

The honest tool hierarchy

Turbo Drive — always active. Intercepts link clicks and form submissions, prevents full page reloads. You’ve been using this since Module 4 without thinking about it.

Turbo Morph — opt-in upgrade to Drive. Instead of replacing the <body>, it diffs and patches. Two meta tags to enable. Controllers stay simple — just redirect as normal.

Turbo Frames — scope a navigation or form submission to a region of the page. Still useful for one specific case: lazy-loading content that shouldn’t block the initial render.

Turbo Streams — targeted DOM surgery from the server. Still useful for two specific cases: re-rendering a form with validation errors in-place (no redirect), and broadcasting real-time updates to other users via ActionCable.

The decision rule

Start with Morph. It handles the vast majority of interactions — creating, updating, and deleting records — with no wiring beyond a redirect. Reach for Frames or Streams only when you hit a specific limitation morphing can’t address.

Throughout this module we’ll follow this rule in the order we hit each limitation. Morph first. Streams for validation errors. Frames for lazy loading. Streams again for real-time broadcasting.