Article  |  Development

Hotwire for Rails Developers: Keeping UI Fast and Maintainable

Reading time: ~ 4 minutes

Hotwire for Rails Developers: Keeping UI Fast and Maintainable

The Challenge of Modern Frontend in Rails

Rails developers often face a dilemma: Should they stick with built-in Rails tools or go all-in on React for interactivity? The rise of JavaScript-heavy apps has made Rails projects harder to maintain. Many teams feel forced to separate the frontend and backend, leading to extra complexity, API management, and more dependencies to manage. While React is powerful, it often adds more overhead than necessary for traditional Rails apps.

But what if you could build a modern, dynamic UI without the extra complexity?

Enter Hotwire – A Rails-native alternative

Hotwire embraces the power of server-rendered HTML while still delivering a fast, interactive user experience. Instead of shifting everything to the frontend, it keeps Rails at the core and handles interactivity in a way that feels natural to the framework.

With Hotwire, you don’t need to set up a separate API, manage client-side state, or keep up with endless JavaScript updates. You get the best of both worlds—modern UI interactions without the React overhead.

What is Hotwire? A Rails Developer’s Perspective

Hotwire is a framework that brings modern UI interactivity to Rails without the complexity of a full JavaScript frontend. It keeps things simple by relying on server-rendered updates instead of pushing everything to the client.

At its core, Hotwire = Turbo + Stimulus:

  • Turbo – Handles fast page loads, real-time updates, and partial page changes without writing custom JavaScript. This means forms, lists, and UI interactions feel instant without managing the frontend state.
  • Stimulus – A small JavaScript framework that adds enhancements where needed. Unlike React, it doesn’t take over the UI—it simply connects behavior to existing HTML elements.

Why Hotwire Fits Rails So Well

Rails has always been about "convention over configuration." Instead of forcing developers to make endless decisions about frontend architecture, Hotwire follows Rails’ principles:

  • It works out of the box with Rails' existing tools.
  • It keeps backend logic in Rails instead of spreading it across multiple layers.
  • It reduces unnecessary complexity by avoiding heavy JavaScript frameworks.

With Hotwire, you don’t need to rework how your app is built—you just extend Rails' strengths to create a fast, interactive UI with minimal effort.

When to Use Hotwire Instead of React

There are many cases where React is overkill in a Rails app. If you don’t need a full-blown single-page application (SPA), React might be adding more complexity than value.

When React is Overkill

  • Your app isn’t an SPA, but it still has some interactive elements.
  • You’re using React for only a few small features (modals, forms, or UI updates).
  • You’re dealing with long build times, slow initial page loads, or performance issues caused by client-side rendering.

When Hotwire Shines

  • You want to keep your app fully within Rails without adding a separate frontend framework.
  • You need real-time updates but don’t want to set up WebSockets manually.
  • You prefer less JavaScript and more of Rails' simplicity.

Hotwire is a great choice for those who want modern UI features without the complexity of a JavaScript-heavy setup. It lets you build fast, interactive apps while keeping your Rails app clean and maintainable.

Hotwire in Action: How We Use it at Planet Argon

In our recent project for Olsson Roofing, we built a mobile-first web application for field maintenance workers. Instead of using React as we typically would, we embraced Hotwire—Rails' modern approach to building responsive web applications without writing much JavaScript.

Turbo Streams for Form Steps

One of our main uses of Hotwire was implementing a multi-step form process for roof inspections. We used Turbo Streams to navigate different form sections without full page reloads. When users submit a form step, the controller responds with a Turbo Stream that updates just the form content:

code snippet showing updates to the form content

The form partial is structured to work with these Turbo Stream updates:

code snippet showing Turbo Stream updates

This approach allowed us to:

  • Keep each form step isolated and maintainable
  • Provide instant feedback when moving between steps
  • Maintain a smooth user experience on mobile devices with slower connections
  • Handle form validation errors without losing context

Stimulus for Enhanced Interactivity

While Turbo handled most of our needs, we used Stimulus for client-side interactions that required JavaScript. Looking at our views, we can see how we connected Stimulus controllers:

code snippet to see how we connected Stimulus controllers

This data-controller="form" attribute connects to our form controller that handles image previews:

code snippet showing data controller form

The controller is automatically loaded thanks to our Stimulus configuration in app/javascript/controllers/index.js:

code snippet showing controllers in javascript

What We Learned

The Good

  • Productivity Boost: Hotwire allowed us to build interactive features with significantly less code than a React-based approach.
  • Performance: Thanks to Turbo's smart HTML streaming, the app feels snappy even on slower mobile connections.

The Challenging

  • Mental Model Shift: Coming from React, it took time to shift our thinking from client-side state management to server-side HTML updates.
  • Debugging: Initially, debugging Turbo Frame and Stream issues was tricky since they operate differently from traditional AJAX requests.
  • Documentation: While Hotwire's documentation is good, finding solutions for edge cases sometimes required diving into source code or community discussions.

What We'd Do Differently

  • Frame Organization: We would better organize our Turbo Frames hierarchy. For example, we could have nested frames for related form sections to better manage state:

code snippet to show frame organization

  • Stimulus Controllers: Instead of the somewhat monolithic form controller we ended up with, we would create more focused, reusable stimulus controllers.

  • Error Handling: We'd implement more robust error handling for Turbo requests, possibly with a dedicated error Stimulus controller:

code snippet showing error handling

FAQ’s and Resources

Key Takeaways

Our experience with Hotwire has been largely positive. While there was a learning curve, the benefits of simpler code, better performance, and enhanced reliability made it a great choice for this mobile-first application. The framework's approach to progressive enhancement particularly shined in our use case, where network connectivity couldn't be guaranteed.

We're excited to continue using Hotwire for future projects, applying the lessons we've learned to build even better applications. The framework's alignment with Rails' "convention over configuration" philosophy means we can focus more on solving business problems and less on technical implementation details.

Have a project that needs help?