Rails Development

Why I Chose Hotwire Over React (As a Beginner)

When I started learning web development, everyone was talking about React, Vue, and Angular. "You need to learn a JavaScript framework," they said. "Single Page Applications are the future."

But then I discovered Hotwire, and it changed everything. In this post, I'll explain why I chose Hotwire over React as a beginner, and why it might be the right choice for you too.

The JavaScript Framework Overwhelm

Before diving into Hotwire, let me paint a picture of what learning React felt like as a beginner:

The React Learning Curve

// Just to display a list of tasks, I needed to understand:
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function TaskList() {
  const [tasks, setTasks] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetchTasks();
  }, []);

  const fetchTasks = async () => {
    try {
      const response = await axios.get('/api/tasks');
      setTasks(response.data);
      setLoading(false);
    } catch (error) {
      console.error('Error fetching tasks:', error);
      setLoading(false);
    }
  };

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      {tasks.map(task => (
        <div key={task.id}>{task.title}</div>
      ))}
    </div>
  );
}

What I had to learn for this simple feature:
- JSX syntax
- useState and useEffect hooks
- Async/await and promises
- API calls with axios
- State management
- Component lifecycle
- Error handling
- Build tools (Webpack, Babel)
- Node.js and npm

The Complexity Spiral

As my React apps grew, so did the complexity:
- State management libraries (Redux, Zustand)
- Routing libraries (React Router)
- Form libraries (Formik, React Hook Form)
- HTTP libraries (Axios, Fetch)
- Build configurations
- Testing frameworks
- Type checking (TypeScript)

I was spending more time learning JavaScript tooling than building features.

Discovering Hotwire

Then I found Hotwire, and everything clicked. Here's how the same task list looks with Hotwire:

The Hotwire Approach

Controller (Ruby):

# app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  def index
    @tasks = current_user.tasks
  end
end

View (ERB):

<!-- app/views/tasks/index.html.erb -->
<h1>My Tasks</h1>

<div id="tasks">
  <%= render @tasks %>
</div>

Partial:

<!-- app/views/tasks/_task.html.erb -->
<div class="task">
  <%= task.title %>
</div>

That's it. No JavaScript, no build tools, no complex state management. The same feature that took dozens of lines of React code works with just a few lines of Rails.

Why Hotwire Made Sense for Me

1. One Language, One Framework

With Hotwire, I could focus on mastering Ruby and Rails instead of context-switching between:
- Ruby for the backend
- JavaScript for the frontend
- Different patterns and conventions
- Separate deployment processes

2. Progressive Enhancement

Hotwire starts with server-rendered HTML that works without JavaScript, then enhances it:

<!-- This works even if JavaScript fails -->
<%= form_with model: @task do |form| %>
  <%= form.text_field :title %>
  <%= form.submit "Create Task" %>
<% end %>

<!-- Hotwire makes it feel like a SPA -->
<%= form_with model: @task, data: { turbo_frame: "tasks" } do |form| %>
  <%= form.text_field :title %>
  <%= form.submit "Create Task" %>
<% end %>

3. No Build Step

With React, every change required:

npm run build
# Wait for webpack to bundle everything
# Refresh browser
# Debug source maps

With Hotwire:
```bash

Just refresh the browser

Everything works instantly


### 4. **Familiar Patterns**

Hotwire extends Rails patterns I already knew:
- Controllers handle requests
- Views render HTML
- Models manage data
- Routes define URLs

React required learning entirely new patterns:
- Components and props
- State and effects
- Context and providers
- Reducers and actions

## Real-World Example: Adding Real-Time Features

Let's say I want to add real-time task updates. Here's how each approach looks:

### React Approach

```javascript
// Need WebSocket library
import io from 'socket.io-client';

function TaskList() {
  const [tasks, setTasks] = useState([]);

  useEffect(() => {
    const socket = io('/tasks');

    socket.on('task_created', (task) => {
      setTasks(prev => [...prev, task]);
    });

    socket.on('task_updated', (updatedTask) => {
      setTasks(prev => prev.map(task => 
        task.id === updatedTask.id ? updatedTask : task
      ));
    });

    return () => socket.disconnect();
  }, []);

  // ... rest of component
}

Hotwire Approach

# app/models/task.rb
class Task < ApplicationRecord
  after_create_commit -> { broadcast_prepend_to "tasks" }
  after_update_commit -> { broadcast_replace_to "tasks" }
end
<!-- app/views/tasks/index.html.erb -->
<%= turbo_stream_from "tasks" %>

<div id="tasks">
  <%= render @tasks %>
</div>

The Hotwire version is simpler, requires no JavaScript knowledge, and leverages Rails conventions I already understand.

When Hotwire Might Not Be Right

To be fair, Hotwire isn't perfect for every situation:

React Might Be Better For:

  • Highly interactive UIs - Complex dashboards, games, drawing apps
  • Offline-first apps - Apps that need to work without internet
  • Mobile apps - React Native for cross-platform mobile
  • Large frontend teams - When you have dedicated frontend developers
  • Complex client-side logic - Heavy calculations, data transformations

Hotwire Excels At:

  • Traditional web apps - CRUD applications, blogs, e-commerce
  • Small teams - Full-stack developers wearing many hats
  • Rapid prototyping - Getting ideas to market quickly
  • Server-side strengths - Leveraging Rails' ecosystem
  • Progressive enhancement - Apps that work without JavaScript

The Learning Path Difference

React Learning Path:

  1. Learn JavaScript (ES6+)
  2. Learn React basics (components, JSX)
  3. Learn React hooks (useState, useEffect)
  4. Learn state management
  5. Learn routing
  6. Learn build tools
  7. Learn testing
  8. Learn backend integration
  9. Start building features

Hotwire Learning Path:

  1. Learn Rails basics
  2. Add data-turbo-frame to forms
  3. Add turbo_stream_from for real-time
  4. Start building features

With Hotwire, I was building real features by day 3. With React, I was still setting up my development environment.

Performance Considerations

One concern people raise about Hotwire is server load. Here's what I've found:

React Performance:

  • Initial load: Large JavaScript bundles
  • Runtime: Fast client-side interactions
  • Server: Minimal load (API calls only)
  • Caching: Complex client-side caching

Hotwire Performance:

  • Initial load: Fast server-rendered HTML
  • Runtime: Small network requests for updates
  • Server: Higher load (but cacheable)
  • Caching: Simple server-side caching

For most applications, server-side rendering is actually faster and more reliable than client-side rendering.

Developer Experience

React Development:

# Start frontend server
npm start

# Start backend server (separate terminal)
rails server

# Run tests (another terminal)
npm test

# Build for production
npm run build

Hotwire Development:

# Start server
rails server

# That's it

The simplicity is liberating. I spend time building features, not managing toolchains.

My Recommendation

Choose Hotwire if you:
- Are learning web development
- Want to focus on one language/framework
- Are building traditional web applications
- Value simplicity over complexity
- Want to ship features quickly
- Are working on a small team

Choose React if you:
- Are building highly interactive UIs
- Have dedicated frontend developers
- Need offline functionality
- Are building mobile apps
- Have complex client-side requirements

The Hybrid Approach

You don't have to choose exclusively. Many successful apps use:
- Hotwire for 90% of the application
- React for specific interactive components
- Stimulus for small JavaScript enhancements

This gives you the best of both worlds.

What I've Built with Hotwire

Since choosing Hotwire, I've built:
- A task management app with real-time updates
- A blog with instant comment posting
- An e-commerce site with dynamic cart updates
- A chat application with live messaging

All without writing complex JavaScript or managing build tools.

The Mental Model Shift

The biggest difference isn't technical—it's mental:

React mindset: "How do I manage state and sync it with the server?"

Hotwire mindset: "How do I make server-rendered HTML feel interactive?"

For me, the Hotwire mindset aligned better with how I think about web applications.

Conclusion

Choosing Hotwire over React as a beginner was one of my best decisions. It allowed me to:
- Focus on learning one framework deeply
- Ship features faster
- Avoid JavaScript framework fatigue
- Build on Rails' mature ecosystem
- Keep my applications simple and maintainable

This doesn't mean React is bad—it's an excellent tool for certain use cases. But for beginners building traditional web applications, Hotwire offers a more approachable path to modern, interactive web apps.

Key takeaways:
- Hotwire extends Rails patterns you already know
- No build tools or complex JavaScript required
- Progressive enhancement keeps apps accessible
- Real-time features are simpler to implement
- Focus on building features, not managing tools

In my next post, I'll show you how to build your first Hotwire feature with Turbo Frames, turning a traditional form submission into an instant, no-refresh experience.


Next up: "Turbo Frames: My First 'Wow' Moment with Hotwire" - We'll build an interactive feature that updates without page refreshes.

Christopher Lim

Christopher Lim

Rails developer and Unity explorer. Family man, lifelong learner, and builder turning ideas into polished applications. Passionate about quality software development and continuous improvement.

Back to All Posts
Reading time: 8 min read

Enjoyed this rails development post?

Follow me for more insights on rails development, Rails development, and software engineering excellence.