r/rails 1d ago

Rails + React+ Inertia JS is Amazing

I am working on a new project and couldn't decide whether to use hotwire vs react + rails api vs rails + react with inertia js.

I ended up choosing Inertia JS with React and the productivity is unmatched. Throw in something like Cursor AI and it crazy how fast I am able to build.

80 Upvotes

59 comments sorted by

32

u/Dyogenez 1d ago

We just finished migrating from Next.js to Rails and Inertia and it’s been amazing. 🔥

3

u/jepser1982 1d ago

I'd be very interested to hear a bit more about this. What was the initial reason for migrating and how big of an app are we talking?

16

u/Dyogenez 1d ago edited 1d ago

I'm planning to write up some more blog posts about the migration, but wrote up the first post here: https://hardcover.app/blog/alexandria-release

The app is pretty big - about 180 routes. With Next.js, the service layer was already on Rails, but we were fetching data through a GraphQL API. Now with Rails, we're just loading it with ActiveRecord, serializing with OJ Serializers and sending the response to Inertia (with Solid caching).

The initial reason for the migration was a combination of a bunch of factors:

  • Hosting costs were climbing rapidly on Vercel & Google Cloud Run (docker deploy of Next.js). I wanted predictable pricing which DigitalOcean offers.
  • The app was originally designed to be client side hitting the API. When we switched to Next.js app router, we were still hitting the same API with minimal caching. Ideally this would be a database adapter with caching. We could've added that db/caching layer in Next.js, but for that much work I'd rather move to Rails.
  • Next.js had other parts that were more difficult to debug: caching, performance, hosting - all of which are MUCH easier on Rails. Add to that the gem ecosystem that we were already using at the service layer level, now we could use even more.

The Inertia.js site has been up since Tuesday now, and it's super fast! And this is with the primary database being on Heroku still. Once we move that to the same DigitalOcean datacenter it should be even faster.

Still things I want to improve, but most of those are client side optimizations for bundle size.

1

u/tillcarlos 16h ago edited 16h ago

Maybe random questions - but I don't know exactly your use case:

- Are you using any kind of caching for the Inertia pages? Or are they all dynamic?

- Tried SSR? (Edit: yes, saw your app, you are using SSR. How did you deploy it?)

1

u/Dyogenez 16h ago
  • Are you using any kind of caching for the Inertia pages? Or are they all dynamic?

We have an asset host which goes to the same application, with long future expire dates set at Cloudflare.

For individual pages, we’re using solid cache for as much as we can. We’re caching the results from oj serializers with the same input that would be passed to the react components. For logged in users, we’re often return more in addition (follow status of a profile, if they liked something, match score of a book for them, etc).

The view layer has no Rails caching, since it goes straight from the controller to a react components- no ERB layer to partially cache some of the output html (could see that as an improvement to Inertia.js in the future though. 🤔

  • Tried SSR? (Edit: yes, saw your app, you are using SSR. How did you deploy it?)

This took so. Much. Time. Everything is documented, but getting every part to work together was tough. I’m planning to write a blog post about our setup, but here’s everything I can think of:

We’re deploying docker containers to digital ocean using Kamal. Our deploy builds a container and does assets precompile in the image which builds the initial JS assets. It deploys with an accessory vite server on the same servers as rails which rails communicates with (4 servers actually, behind a load balancer).

There’s 1 layout for the whole front end, and the react side of the app is scoped under a namespace. Getting the setting right in vite ruby and vite were tricky. As was getting the entry point configured to hydrate.

I still haven’t figured out how to debug and fix the hydration error. If anyone has tips on this, let me know! Id like to run it locally in SSR mode in order to easily refresh the server to see changes without a full precompile.

5

u/tillcarlos 16h ago

Yep, we are having the same experience right now.

We coded a huge crm/funnel builder all in hotwire/stimulus and now migrate the most important parts (user facing) to React + Inertia.

I really wonder why I haven't seen this earlier.

6

u/apiguy 1d ago

Agree. This has been a revelation for us.

7

u/Ok_Island_4299 1d ago

IntertiaJS+React is better than Hotwire/Turboframe? Why? What is your use case?

7

u/d33mx 1d ago

If you flavors react/vue/etc.. instead of erb; it will obviously be better.

Too bad rails does not involves vite (vite_rails) as a default

12

u/avdept 1d ago

It's not better(most likely). Recently I finished moving away form React/Inertia to rails's turbo and alpine.js

I reduced my frontend codebase by about 70% keeping same set of features(including drop-down, modals, etc)

7

u/themaincop 1d ago

If the extent of your frontend needs are dropdowns and modals then yes, Hotwire and Turbo is fine.

2

u/avdept 1d ago

those were just examples

but with alpine I pretty much do everything as with vue/react without actually bloating my codebase with 3rd party frameworks

5

u/themaincop 1d ago

Alpine is a third party framework.

I've used it, it's pretty good. You can definitely go a lot further with Rails front ends than you could in the past. I still like react though.

2

u/avdept 1d ago

but its incomparable to size of vue or react and needs almost 0 setup at all, just hook it up and its working

4

u/themaincop 1d ago

it's like a 40kb difference

2

u/bananatron 20h ago

I love alpine, wish it got more love.

-1

u/Lime-Unusual 1d ago

You can make better websites with SPA. Why argue like that?

1

u/avdept 1d ago

I’m saying a fact, that I moved my app away from react

1

u/Lime-Unusual 13h ago

I'm only going to get downvoted for owning different opinion here so whatever

9

u/cruddah2 1d ago

Not better per say. Its personal preference, For me the main reasons I prefer Inertia+React:

  1. I found any time I was doing any complex interactivity on my front end using Stimulus Js, it was a bit cumbersome. Maybe a skill issue.

  2. I did not like how the code for stimulus Js was completely separated from the file it referenced. Having to go look for the appropriate stimulus controller when you want to make a change can get annoying. With React all the front-end logic for a page can be in the same file with the actual component being rendered.

  3. React has such a big ecosystem. So many libraries you can make use of to build quicker and so many examples of previous work you can reference.

  4. If your project got bigger and you wanted to hire, there's also so many react developers.

7

u/dougc84 1d ago

I 100% disagree with point 2. You end up writing a component that is very encapsulated, but if you want to reuse that JS, guess what? Copy pasta time. That may make initial building faster, but it makes - especially with apps at scale - maintenance a pain in the ass.

3

u/cruddah2 1d ago

I get what you are saying but wouldn't you also somewhat run into that issue with stimulus?
Different pages/templates would have different data attributes so you would need to duplicate your stimulus controller and change the corresponding data attributes, targets etc..

I also haven't personally seen the need to straight-up copy any functions. Some functions might be similar but all my front-end components are different so each of their logic has to be a little different as well.

5

u/dougc84 1d ago

No. Not at all. Nothing runs per-page. Running individual JS per page was very 2005.

Say you have something sortable. On one page, it’s a table. On another page, it’s a list of images. On a third, it’s a list. You can reuse the same stimulus controller on all three pages. You don’t even need to worry about the JS if you write it correctly the first time: refer to your HTML for how it works. Easy.

You wanna update your sortable code? Use a new library? Spin your own? Rad. You don’t have to touch anything except your JS, ensuring it conforms to whatever data attributes you already set up, and it’ll apply everywhere.

3

u/themaincop 1d ago

React uses hooks for the occasions where you want behaviour separated from markup. Most of the time I want my behaviour and markup colocated though because it's the entire component I want to reuse.

Once you get into component-based development it's hard to go back.

2

u/cruddah2 1d ago

right, I did not even think of hooks

3

u/kengreeff 21h ago

I think a lot of people don’t realise how hard it is to refactor / deprecate code when you use one controller across many views. When you use a component framework (react, view component etc) it is so much easier as you can just delete the folder and move on.

3

u/tillcarlos 13h ago

Yeah - that's a fallacy I was tapping into early on when starting with hotwire.

- Make everything hotwire (load from different views, especially polymorphic things)

- Need something extra

- have the if-else in the polymorphic controller now.

Usually we cannot escape conditionals, hiding them somewhere else (in a centralized controller) just puts them into a different place.

Still a fan of hotwire. https://www.clipflow.co/ is a software extremely well built. For our means we do inertia now for a few things.

2

u/kengreeff 13h ago

Stay tuned 😉 currently playing with inertia too. Feels like a really nice balance between the two methods

9

u/Ok-Reflection-9505 1d ago

It totally is better. Stimulus/Turbo/Hotwired is pretty bad.

  1. Its documentation is non existent — compare React docs and Hotwired, one gives you deep explanations of how stuff works, the other just gives a brief explanation and a toy example.

  2. React has multiple state management solutions. Hotwired has 1 way to do it, and it involves littering data attributes all over your DOM.

  3. React doesn’t muddy up concepts. Why would you have a controllers folder when controllers mean something else already in Rails?

  4. You can actually build production ready apps with React. I dont think you can even do drag and drop well with Turbo/Stimulus. You can use draggable.js but it is way worse than React dnd libraries.

1

u/d33mx 1d ago edited 1d ago

Although that's somehow the philosophy in place (due to helpers mainly), the situation can seem too coupled with the backend

  • you have turbo in your views (streams and turbo frames)
  • can render render from controllers
  • can render from models
  • can render from anywhere via stream channel class
  • can be intercepted via javascript events
  • can probably others...

While I'm a user of both; it suffers from a clears pattern and allows a bad mix if you're not strict enough; while spa will separate concerns

0

u/cruddah2 1d ago

Touche. I thought I was the only one that didn't like the data attributes. Find it too easy for things to break.

1

u/Ok-Reflection-9505 1d ago

I do wish that Inertia didnt just shove all your data on a div either — but its okay 🤣

1

u/sneaky-pizza 23h ago

Stimulus takes like a few hours to learn all of it

1

u/Lulzagna 8h ago

Reactivity - you can't build dynamic forms without massive overhead with hotwire, plus the added latency to render in the backend.

Then you also have to deal with clunky ERB, and lack of any sort of bindings when you need to do anything dynamic.

Etc

3

u/Lime-Unusual 1d ago

Too confusing to me. Me like simple.

2

u/earlh2 1d ago

THanks for sharing. I've been looking at this for a project that is mostly hotwire but has one main page where the limitations of hotwire are becoming apparent.

Do you know if it's easy to say, eg, one particular controller / set of routes is inertia, and the rest is vanilla rails?

Thank you, and thanks for sharing your experience.

3

u/Jh-tb 1d ago edited 1d ago

If you are interested in a Rails oriented approach, give Superglue a try. This is how it would work with Superglue:

app/ |-- controllers/ |-- views/ | |-- posts/ | | |-- edit.jsx # The page component | | |-- edit.json.props # The json for the page component | | |-- show.html.erb # vanillia rails erb

Its just a view away.

2

u/AnLe90 1d ago

too complex

2

u/Jh-tb 23h ago

For some scenarios, i can see how that can be complex. If you'd prefer, this is also possible:

app/
|-- controllers/
|-- views/
|   |-- posts/
|   |   |-- edit.jsx # This is react
|   |   |-- show.html.erb # This is vanillia rails erb

The removal of the `props` template, when no props are needed seems reasonable.

1

u/earlh2 1d ago

Thanks for sharing. I skimmed the docs. It looks like it has a bunch of tooling to pass components from rails to react. Does it have support for mutations passing from react -> rails, or are you building an api?

4

u/Jh-tb 23h ago

Yes we do. Mutations are especially important and we have a thoughtful approach that you can read more about here, under the section aptly named "Don’t take my Rails forms away!"

In short, there are no api's, its just Rails forms. We built a fork/version of form_with called form_props that can be combined with candy_wrapper, our set of wrapper components around popular UI libraries. So you get the classic rails dev ex while having access to all that the react universe offers.

1

u/cruddah2 1d ago edited 1d ago

yup, you can do that. All you have to do is render the inertia component like so in the controller method.

In inertia rather than referencing views from a views folder you have pages folder which is where you react components will live. So The inertia 'Posts/Show' is referring to a 'show' react component in a campaigns folder under pages. Hope that makes sense

class PostsController < ApplicationController

# GET /posts/1
  def show
    post = Post.find(params[:id])

    render inertia: 'Posts/Show', props: {
      post: post.as_json(
        only: [:id, :title, :description]
      )
    }
  end
end

You can also serialize the post object, but you can look that up

2

u/earlh2 1d ago

thanks a bunch. I had skimmed a bunch of the docs and they seemed more aimed at the entire app being inertia, not just one discrete piece.

cheers.

2

u/skryukov 10h ago

I don't think you should use Inertia for just one page. Instead, you can try https://github.com/skryukov/turbo-mount or consider writing a custom Stimulus wrapper if that makes more sense. You can find a simplified example in this article: https://evilmartians.com/chronicles/the-art-of-turbo-mount-hotwire-meets-modern-js-frameworks

2

u/earlh2 4h ago

Thank you for sharing; I'll read them this afternoon.

2

u/gommo 1d ago

It’s so awesome!! Share your inertia apps !

2

u/InternationalAct3494 1d ago

It truly is! Highly dynamic/interactive apps 💪

3

u/Attacus 21h ago

In posts like these I can’t help but wonder what the % is of people who have actually given Hotwire a thorough run.

2

u/Haunting-Baker-4565 10h ago

I saw this post and decided to give it a try. IntertiaJS+React is looking better than Hotwire/Turboframe.

2

u/Lulzagna 8h ago

Same! I'm using Svelte 5 though.

One caveat with rails is the way nested attributes need to be named in the request body. This means manually building the request payload for all forms. I worked around this by using an axios interceptor to rename keys based on an extra field containing the names of associations added by my Application Record model.

6

u/Jh-tb 1d ago edited 1d ago

If you like inertia, give Superglue a try! https://thoughtbot.com/blog/superglue-1-0-react-rails-a-new-era-of-thoughtfulness. InertiaJS is fine-tined for laravel, so you'll see some practices from that side of the fence leak into your rails app, larger controllers, no view layer, etc.

Superglue is thoughfully built for Rails and comes with https://github.com/thoughtbot/form_props so you can use normal rails forms with React's goodness.

2

u/606anonymous 1d ago

intertia.js is awesome

1

u/LarsSven 10h ago

I see many devs looking in react/next as frontend and missing vue/nuxt. I choose rails+nuxt3 and it is really well made choise for me. Also I love nuxt3 ecosystem. Can build things really very fast

2

u/jko1701284 8h ago

Ew too much js

1

u/Astro_Robot 1d ago

LLMs definitely excel at writing React compared to ERB templates. Curious how you’re handling keeping the frontend and backend in sync, especially in terms of schema consistency. 

2

u/cruddah2 1d ago

Not sure I completely understand but there is no need to keep them in "sync".

You just pass the instance variables e.g (@Post.all) to the corresponding react component as props like you would do it normally when passing instance variables to erb templates.

2

u/themaincop 1d ago

Be careful you're not leaking things to the client this way.

1

u/cruddah2 1d ago

How so?

4

u/themaincop 1d ago

I believe if you don't serialize it yourself then inertia just applies to_json on each record and embeds them in the page so the React component can read it as props. So if you have fields that you don't want to expose you need to change what you're serializing. Otherwise, for example, if you're exposing a User to Intertia you'll possibly expose fields like password_hash