How to integrate React with Rails 7

We love Ruby on Rails at thoughtbot. And we love JavaScript too. Even with the growing popularity of Hotwire and Stimulus, React is still a popular choice. But it’s not always simple to integrate React with Rails.

What are the options for building a React + Ruby on Rails app?

1. One React app + one Rails app

You can spin up a React app and a separate Rails app and maintain them independently. Two Git repos and two hosting providers. The frontend app talks to Rails using an API layer.

This is nice if you’ve got two separate teams working on them. It’s also nice to host React as static files in something like S3.

We used to spin up a React app using create-react-app but now that it’s deprecated we use Next.js.

Benefits

  • No fighting with the Rails asset pipeline
  • Hosting frontend code on a CDN can really speed up your site
  • React hosting platforms like Vercel or Netlify are lovely to work with
  • Separate frontend and backend teams can work independently
  • A clear separation of the code’s responsibilities

Downsides

  • Double the hosting and infrastructure complexity + costs
  • Building an API layer adds significant work
  • You have to build auth on the frontend and backend and make them work together
  • CORS and cookie sharing limitations when working across domains
  • Code for new features is spread across multiple Git repos

2. Serve React as Rails assets

You can host your React app’s generated JavaScript files inside Rails’s asset pipeline. The Ruby on Rails asset pipeline is in a confusing place right now - there’s been a lot of changes over the past few years.

Here are a couple posts that describe your options for bundling JS assets in Rails 7:

The tl;dr is that in a new Rails 7 app you should use Shakapacker or jsbundling for preprocessing and bundling your JavaScript code.

Benefits

  • There’s just one codebase
  • You only need one build pipeline, hosting provider, and related infrastructure
  • You can choose which pages are rendered with React vs ERB
  • No fighting with CORS and cross-domain cookie limitations

Downsides

  • You still have to build an API layer for communicating between React and Rails
  • You have to figure out how to set up bundling
  • The Rails asset pipeline is constantly evolving
  • It takes extra work to integrate a React dev server for hot module reloading (HMR)

3. React on Rails

React on Rails is a nice pre-built integration of React and Rails. You can avoid doing the plumbing work yourself. It also lets you pass in Ruby variables as props so you don’t need to build a JSON API. And it supports Server-side rendering (SSR) of React screens.

React on Rails has superseded the older React Rails tool.

thoughtbotter Sarah Lima wrote about using React on Rails recently in this post.

Benefits

  • It supports advanced rendering features like server-side rendering and code splitting
  • You can pass variables from Rails into React as Props
  • You don’t have to build an API layer
  • You can use Rails localization features in React
  • It mostly sorts out the asset pipeline problems for you
  • You can use React on some pages, all pages, or even parts of pages

Downsides

  • You need to register your components before you can use them
  • Your React code is tightly coupled with Rails

4. Superglue

At thoughtbot, we created Superglue to make working with React as easy as Hotwire. It sets up your project to use React (no need for APIs) without giving up any of the Rails goodness. The flash, cookie auth and url helpers all work like you expect. We even forked form_with so you can use Rails form helpers with React.

It’s like replacing the view (ERB) with React as a view, while giving you an escape hatch for more interactive things that React is well suited for.

You can find more details in Johny’s blog post.

Benefits

  • It feels very familiar to experienced Rails users
  • It’s easy to build React forms in a Rails-like way (I’m a big fan of the Rails form builder)
  • You don’t have to build an API layer
  • It’s easy to pass even complicated objects and arrays from Rails to React
  • Support for SSR
  • You get SPA-style navigation and partial component updates

Downsides

  • Your React code is tightly coupled with Rails - even more so than React on Rails
  • There’s a learning curve for figuring out the data flow into and out of React
  • It’s not out of beta yet

Where to start?

As you review these options, which pros and cons resonate with you? Your level of experience with React and Rails, and your team size, will probably influence your choice. Don’t be afraid to experiment.

So what did we choose?

  • I recently worked on a Rails 7 app that had some ERB pages and some React pages. We used a beta version of Superglue.
  • Last year I worked on a Rails 7 app where almost all pages were built with React. We hosted React in the asset pipeline with jsbundling, with a custom esbuild script to support esbuild plugins.
  • Another thoughtbotter just started a project that has a lot of forms. They’re using Superglue to take advantage of the new form_props features.
  • A different thoughtbotter used the Rails asset pipeline along with Vite, although there were plans to move from Vite to jsbundling.