docs/oss/migrating/migrating-from-react-rails.md
This migration is easiest when the app is already on a modern Rails + Shakapacker baseline.
Before swapping gems, check these first:
webpacker, migrate to shakapacker first.react-rails apps still carry Bundler 1.x lockfiles. Those can fail on modern Ruby before you even reach the migration work.react_on_rails requires Rails 5.2+. Rails 5.1 / Webpacker 3 apps are usually a staged migration, not a one-command migration.yarn.lock, pnpm-lock.yaml, or bun.lock*, ensure package.json has a matching packageManager field (for example [email protected], [email protected], [email protected], or [email protected])..browserslistrc exists, remove browserslist from package.json..js files. If your project has custom transpiler setup, review config/shakapacker.yml after generation.If you are already on shakapacker 7+ and React 18+, the migration is mostly about helper syntax, component registration, and generated defaults.
If bundle install fails before you even start because the lockfile was generated by Bundler 1.x, refresh the lockfile with a modern Bundler first:
bundle _2.3.26_ lock --update
bundle _2.3.26_ install
If package.json is missing packageManager, set it to your project's actual manager and exact version before running install generators:
# pick the one that matches your lockfile
npm pkg set packageManager='[email protected]'
npm pkg set packageManager='[email protected]'
npm pkg set packageManager='[email protected]'
npm pkg set packageManager='[email protected]'
Update Deps
react-rails in Gemfile with react_on_rails and make sure shakapacker is present.react_ujs from package.json.bundle install and your package manager's install command.Run rails g react_on_rails:install but do not commit the change. react_on_rails attempts to install node dependencies, creates a sample React component, Rails view/controller, and updates config/routes.rb. If dependency installation fails, the generator prints manual install commands. If required package-manager tooling (Node.js and npm/yarn/pnpm/bun) is unavailable, the generator stops with setup guidance. Run the suggested commands or install missing tools before continuing.
Adapt the project: Check the changes and carefully accept, reject, or modify them as per your project's needs. Besides changes in config/shakapacker or babel.config which are project-specific, here are the most noticeable changes to address:
Check Webpack config files at config/webpack/*. If coming from react-rails v3 on Shakapacker, the changes are usually localized. The most important difference is the server bundle entrypoint: react-rails commonly uses server_rendering.js, while React on Rails defaults to server-bundle.js.
In app/javascript directory you may notice some changes.
react_on_rails can work with manual registration or the newer auto-bundling flow. Auto-bundling is usually the cleaner target for new work.
react_on_rails uses server-bundle.js instead of server_rendering.js. If you keep your old filename, update the generated config accordingly.
Replace ReactRailsUJS mounting with explicit React on Rails registration. The generated files show the current registration pattern.
Check Rails views. In react_on_rails, react_component view helper works slightly differently. It takes two arguments: the component name, and options. Props is one of the options. Take a look at the following example:
- <%= react_component('Post', { title: 'New Post' }, { prerender: true }) %>
+ <%= react_component('Post', { props: { title: 'New Post' }, prerender: true }) %>
Validate before final cleanup:
Confirm that old react_ujs references are gone:
rg -n "react_ujs|ReactRailsUJS|server_rendering\.js" app/javascript app/assets app/views config
# or without ripgrep:
grep -rn "react_ujs\|ReactRailsUJS\|server_rendering\.js" app/javascript app/assets app/views config
Ensure compile succeeds:
bundle exec rails shakapacker:compile
Review react_component helper calls to ensure they use options-style props:
rg -n "react_component\\b" app/views
# or without ripgrep:
grep -rEn "react_component\\b" app/views
These commands list candidates only. Inspect each match manually and convert any legacy positional calls
(for example react_component('Post', @props, prerender: true), react_component 'Post', @props,
react_component :Post, @props, or react_component component_name, @props) to options-style props
before running tests.
Run your test suite and fix any app-specific breakages before merging.
Older react-rails apps frequently need these additional fixes after the generator run:
Remove old UJS mounting from legacy packs (app/javascript/packs/application.js and related files).
Remove patterns such as:
var componentRequireContext = require.context('components', true);
var ReactRailsUJS = require('react_ujs');
ReactRailsUJS.useContext(componentRequireContext);
If you are switching to React on Rails server-bundle.js, remove stale app/javascript/packs/server_rendering.js usage.
Update existing ERB helper calls from old positional props to options-style props:
- <%= react_component 'Post', @props, prerender: true %>
+ <%= react_component('Post', { props: @props, prerender: true }) %>
If server bundles are not being found, verify config/initializers/react_on_rails.rb setup:
private_output_path. Leave this unset unless you intentionally need an override.config.server_bundle_output_path = "ssr-generated"
If spec/rails_helper.rb gets a malformed merge after generator updates, keep a single valid RSpec.configure do |config| ... end block and include:
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
You can also check react-rails-to-react-on-rails branch on react-rails example app for an example of migration from react-rails v3 to react_on_rails v13.4.
For a more recent Rails 7-era migration example (published under ShakaCode), see react-on-rails-migration-example, based on ganchdev/react-rails-example.
If your app looks like this:
gem "webpacker" in Gemfilereact_ujs in package.jsonapp/javascript/packs/application.jsapp/javascript/packs/server_rendering.jsthen treat the migration as:
webpacker to shakapacker.react_on_rails.react_ujs.bin/dev, config/shakapacker.yml, and webpack config diffs before committing.