React on Rails Migration Examples: Meta Tracking Issue
This issue tracks open-source Rails applications that are strong candidates for incremental migration to react_on_rails, along with the public PRs, blockers, benchmark notes, and follow-up work.
Public docs should only carry durable example references. This issue is the better home for in-progress third-party PRs, maintainer-contact notes, and other working material that may change quickly.
The goal is not to rewrite large apps wholesale. The goal is to prove a repeatable migration path from existing Rails-plus-React stacks such as react-rails, webpacker, shakapacker, vite_rails, and custom Rails React bridges.
Why This Matters
Teams evaluating react_on_rails want proof from real applications, not only toy examples.
The most credible evidence is:
- Real open-source Rails repos
- Narrow migration PRs
- Reproducible before-and-after notes
- Performance or maintainability evidence for each migrated slice
Selection Policy
- Prefer very popular or institutionally credible Rails applications.
- Favor apps already using React with Rails in some form.
- Keep the first PR small enough to review quickly.
- Avoid obscure dependencies or novelty migrations that do not help the main adoption story.
- Treat Inertia-first apps as stretch targets unless the point is to document architecture differences.
First-Wave Status
| Repo |
Stars |
Current Integration |
Status |
PR |
Evidence so far |
Missing proof |
EFForg/action-center-platform |
517 |
react-rails |
PR ready for review |
#975 |
Contributor-local benchmark note captured: warm request time and total JS weight both decreased for the slice; local maintainability note is captured for the new explicit Rails prop boundary and the narrowed page-scoped React on Rails entrypoint; local webpack compilation passes, the repo Docker build now passes with the Node 20 + Yarn-aligned container fix, and compose-backed db:test:prepare plus the focused request/helper specs pass |
Optional browser-level proof if a maintainer asks for stronger route evidence; otherwise the next step is maintainer review |
thewca/worldcubeassociation.org |
383 |
react-rails |
PR ready for review and mergeable |
#14010 |
Local maintainability note captured for the legacy disclaimer page; after rebasing onto upstream main, the compose-backed disclaimer request spec, Shakapacker build, Corepack Yarn lint, and focused RuboCop all pass with the legacy-helper coexistence override |
Optional CI confirmation or one more low-risk legacy Rails slice if maintainers want broader proof; otherwise the next step is maintainer review |
demarche-numerique/demarche.numerique.gouv.fr |
259 |
vite_rails + custom React bridge |
Closed after maintainer feedback |
#12954 |
Focused component spec passed; local maintainability note captured for replacing a custom coldwired/react mount contract with a maintained helper contract |
External blocker: maintainer said the repo depends on coldwired updating React components during DOM morphs, so this migration slice is not a fit for their architecture |
GSA/search-gov |
68 |
react-rails + Shakapacker |
PR rebased and mergeable; CircleCI in progress |
#2010 |
Branch rebased onto upstream main at fa0ea57fb; focused Jest passes locally for SearchResultsLayout, SearchResultsHeader, and SearchResultsFooter; GitHub now reports the PR as mergeable; CircleCI is in progress after the force-push with checkout code and jest green while rspec and cucumber are still pending; local maintainability note captured for splitting low-coupling SERP chrome into smaller mounts; PR rationale already explains the maintainability-first value of shrinking the shell boundary without rewriting the results body |
Wait for the remaining CircleCI jobs; optional public-friendly benchmark note if stronger marketing proof is needed; otherwise the next step is maintainer review |
hackclub/hcb |
845 |
react-rails |
PR ready for review and mergeable |
#13489 |
After rebasing onto upstream main, the repo Dockerfile rebuilds successfully, compose-backed db:test:prepare plus the focused bookkeeping controller spec pass, yarn build, yarn build:css, focused RuboCop, and yarn lint all pass once the app uses an explicit React-on-Rails alias plus a legacy-helper coexistence override; local maintainability note is captured for that coexistence path; asset-level comparison shows bundle.js moved from 2,739,714 to 2,754,760 bytes while yarn build improved from 10,035 ms to 9,101 ms |
Optional browser-level pass if stronger public performance proof is needed; otherwise the next step is maintainer review |
broadinstitute/single_cell_portal_core |
70 |
vite_rails + custom window.SCP.renderComponent bridge |
Draft PR open |
#2381 |
Local helper-test, focused Jest, and vite build --force --clear all pass for the studies#usage_stats slice; asset-level comparison shows application-*.js moved from 2,083,391 to 2,099,314 bytes while full rebuild time moved from 22,947 ms to 23,486 ms |
Controller/request-level HTML proof once Mongo-backed test auth is available |
Second-Wave Targets
These matter, but they are weaker first proof points than the current wave.
| Repo |
Stars |
Current Integration |
Current status |
thecartercenter/nemo |
65 |
react-rails + shakapacker |
PR ready for review: #1110. Fresh local db:setup, compile, react_on_rails:doctor, request spec, system spec, RuboCop, and focused JS lint all pass; shared global components chunk dropped from 305,252 to 293,091 bytes; request harness measured 35.01 ms / 32,009 HTML bytes / 11 script tags baseline versus 44.20 ms / 33,068 HTML bytes / 16 script tags migrated, so the honest claim is maintainability plus shared-bundle reduction, not route-level speedup |
Codeminer42/cm42-central |
324 |
vite_rails + React |
Draft PR open: #1029. Local Docker/Linux validation passes: db:setup, focused controller spec, focused JS specs, ESLint, and vite build all succeed; the built application-*.js bundle moved from 2,193,537 to 2,209,328 bytes; request harness measured /projects at 39.74 ms / 8,081 HTML bytes / 6 scripts baseline versus 45.62 ms / 7,746 HTML bytes / 8 scripts migrated, so this remains a maintainability-first slice |
broadinstitute/single_cell_portal_core |
70 |
vite_rails + custom window.SCP.renderComponent bridge |
Draft PR open: #2381. Local helper-test, focused Jest, and vite build --force --clear pass; the built application-*.js bundle moved from 2,083,391 to 2,099,314 bytes |
indentlabs/notebook |
398 |
react-rails + Webpacker (ReactRailsUJS auto-mount) |
Compile still passes locally, but a real landing-page request now fails because the migrated helper expects config/shakapacker.yml; the branch is therefore blocked on whether to add real Shakapacker config or stage a broader migration first |
saeloun/miru-web |
256 |
vite_rails + SPA root |
Local Ruby and package installs pass, but the router still falls through home#index into one global Vite entrypoint that mounts a single #react-root, so this is an app-shell case study rather than an incremental island migration |
codeforpdx/dwellingly-app |
49 |
react-rails with SPA routing |
Local work is blocked by the pinned Ruby 3.0.1 not building on this macOS arm64 host |
rubyforgood/demand-progress |
56 |
Webpacker + ad hoc React mount |
Local work is blocked by the locked Ruby 2.5.1 not building on this macOS arm64 host |
Stretch and Blocked Targets
| Repo |
Status |
Reason |
antiwork/gumroad |
Stretch target |
Important repo, but it is Inertia-first and is not the cleanest first proof point |
exercism/website |
Process-blocked |
Useful technically, but the repo documents that outside PRs are not accepted |
Whale Targets
These are the high-value proof points that should come after the first wave is clearly credible.
| Repo |
Stars |
Current Integration |
Notes |
mastodon/mastodon |
49,825 |
vite_rails + React |
Probably the most visible Rails + React migration story if a narrow slice can be found |
gitlabhq/gitlabhq |
24,295 |
vite_rails + React |
Worth documenting, but too broad for the first implementation wave |
Institutional Middle Tier
These are not whales, but they are still strong proof points once the first wave is done.
| Repo |
Stars |
Current Integration |
Why it matters |
Recommendation |
thecartercenter/nemo |
65 |
react-rails + shakapacker |
Institutionally credible and still close to the classic migration story |
Keep using ready PR #1110 as the second-wave institutional proof point; the first slice is maintainability-first, shows an honest shared-bundle reduction and clean coexistence path, and now explicitly documents that the admin route itself is not faster in the local request harness |
Codeminer42/cm42-central |
324 |
vite_rails + React |
Strong star count and real page-scoped mounts instead of a catch-all SPA shell |
Move this up with nemo; draft PR #1029 is now open for the validated projects.index slice with asset and request-harness notes |
broadinstitute/single_cell_portal_core |
70 |
vite_rails + custom window.SCP.renderComponent bridge |
Broad Institute credibility plus a repo-owned Rails-to-React mount contract makes it a meaningful non-demo proof point |
Promote alongside cm42-central; draft PR #2381 is open for the validated studies#usage_stats slice, and the remaining gap is Mongo-backed controller/request proof |
digitalepidemiologylab/crowdbreaks |
12 |
Webpacker + webpacker-react |
Research-institution ownership gives it some signal, but it is the weakest of this tier |
De-prioritize behind the other institutional targets |
Reference Repos Already On React on Rails
These are useful references. Some are also legitimate upgrade-PR candidates.
| Repo |
Current stack snapshot |
Upgrade fit |
Recommendation |
ifmeorg/ifme |
react_on_rails 12.0.1, webpacker 5.4.4, React 17 |
Strong |
Fork branch justin808/ifme:codex/upgrade-react-on-rails-16 is pushed and locally revalidated; upstream PR is blocked only by the project's Slack-first contribution process |
houdiniproject/houdini |
gem react_on_rails 12.6.0, JS package 12.2.0, webpacker 5.4.4, React 17 |
Strong |
Still worth an upgrade PR, but current local work is blocked before app code because Ruby 3.0.7 is brittle on this macOS arm64 host and the patched local install was not healthy enough to run Bundler |
avalonmediasystem/avalon |
react_on_rails 14.2.1, shakapacker 8.3.0, React 19 |
Good |
Queue after ifme and houdini, but first fix the missing pinned active-fedora git revision in the baseline app |
sharetribe/sharetribe |
react_on_rails 13.0.2, React 16 |
Weak |
Do not prioritize; the repo says it is no longer actively maintained |
hostolab/covidliste |
react_on_rails 12.2.0, webpacker 5.3.0, React 17, Node 12 |
Weak |
Do not prioritize; activity looks too stale for unsolicited upgrade work |
Known Cross-Cutting Blockers
- Existing Rails apps use materially different integration stacks, so this is not a single codemod problem.
- Some repos have heavy local setup or native dependency chains that block fast validation, so benchmark and request-proof notes need a pinned Docker or service-backed environment instead of a half-working host install.
- Large repos often require very narrow PR scope to be reviewable upstream.
- Performance or maintainability evidence needs a shared method or the results will not be credible.
Related Issues and PRs
- Docs PR: #3126 merged
- Proof-artifacts issue: #3127
- Legacy Webpacker compatibility follow-up: #3136
- React 16/17
react-dom/client warning follow-up: #3137
- Docs follow-up for legacy migration guidance: #3138
- Helper-name collision follow-up: #3143
- Vite package-manager check follow-up: #3145
- Nested
client/ package layout follow-up: #3205
- Related but different scope: #1985 for RSC migration success stories
- Framework-level benchmarking issue: #2169
- Benchmark workflow issue: #2546
What Is Still Missing
- A public-friendly publication path for the local proof notes now that the example-migrations docs page has landed
- A public browser benchmark note for at least one more repo beyond ACP.
nemo now has both asset and request-harness notes, but the request result is maintainability-first rather than a speedup story and it still needs a browser waterfall pass before it becomes a stronger public benchmark
- A decision on whether Gumroad stays in the migration queue or becomes an Inertia case study
- A later whale-target scouting pass once the first wave lands
- A decision on which institutional middle-tier repo should become the next serious target after the current wave once
nemo maintainer feedback lands
- A reusable benchmark environment for side-by-side demos and videos that includes the service dependencies some apps need for request-level proof
- A product/docs answer for supported upgrades where JS dependencies intentionally live under
client/ rather than the Rails root
React on Rails Migration Examples: Meta Tracking Issue
This issue tracks open-source Rails applications that are strong candidates for incremental migration to
react_on_rails, along with the public PRs, blockers, benchmark notes, and follow-up work.Public docs should only carry durable example references. This issue is the better home for in-progress third-party PRs, maintainer-contact notes, and other working material that may change quickly.
The goal is not to rewrite large apps wholesale. The goal is to prove a repeatable migration path from existing Rails-plus-React stacks such as
react-rails,webpacker,shakapacker,vite_rails, and custom Rails React bridges.Why This Matters
Teams evaluating
react_on_railswant proof from real applications, not only toy examples.The most credible evidence is:
Selection Policy
First-Wave Status
EFForg/action-center-platformreact-railsdb:test:prepareplus the focused request/helper specs passthewca/worldcubeassociation.orgreact-railsmain, the compose-backed disclaimer request spec, Shakapacker build, Corepack Yarn lint, and focused RuboCop all pass with the legacy-helper coexistence overridedemarche-numerique/demarche.numerique.gouv.frvite_rails+ custom React bridgecoldwired/reactmount contract with a maintained helper contractcoldwiredupdating React components during DOM morphs, so this migration slice is not a fit for their architectureGSA/search-govreact-rails+ Shakapackermainatfa0ea57fb; focused Jest passes locally forSearchResultsLayout,SearchResultsHeader, andSearchResultsFooter; GitHub now reports the PR as mergeable; CircleCI is in progress after the force-push withcheckout codeandjestgreen whilerspecandcucumberare still pending; local maintainability note captured for splitting low-coupling SERP chrome into smaller mounts; PR rationale already explains the maintainability-first value of shrinking the shell boundary without rewriting the results bodyhackclub/hcbreact-railsmain, the repoDockerfilerebuilds successfully, compose-backeddb:test:prepareplus the focused bookkeeping controller spec pass,yarn build,yarn build:css, focused RuboCop, andyarn lintall pass once the app uses an explicit React-on-Rails alias plus a legacy-helper coexistence override; local maintainability note is captured for that coexistence path; asset-level comparison showsbundle.jsmoved from2,739,714to2,754,760bytes whileyarn buildimproved from10,035 msto9,101 msbroadinstitute/single_cell_portal_corevite_rails+ customwindow.SCP.renderComponentbridgevite build --force --clearall pass for thestudies#usage_statsslice; asset-level comparison showsapplication-*.jsmoved from2,083,391to2,099,314bytes while full rebuild time moved from22,947 msto23,486 msSecond-Wave Targets
These matter, but they are weaker first proof points than the current wave.
thecartercenter/nemoreact-rails + shakapackerdb:setup, compile,react_on_rails:doctor, request spec, system spec, RuboCop, and focused JS lint all pass; shared global components chunk dropped from305,252to293,091bytes; request harness measured35.01 ms/32,009HTML bytes /11script tags baseline versus44.20 ms/33,068HTML bytes /16script tags migrated, so the honest claim is maintainability plus shared-bundle reduction, not route-level speedupCodeminer42/cm42-centralvite_rails+ Reactdb:setup, focused controller spec, focused JS specs, ESLint, andvite buildall succeed; the builtapplication-*.jsbundle moved from2,193,537to2,209,328bytes; request harness measured/projectsat39.74 ms/8,081HTML bytes /6scripts baseline versus45.62 ms/7,746HTML bytes /8scripts migrated, so this remains a maintainability-first slicebroadinstitute/single_cell_portal_corevite_rails+ customwindow.SCP.renderComponentbridgevite build --force --clearpass; the builtapplication-*.jsbundle moved from2,083,391to2,099,314bytesindentlabs/notebookreact-rails + Webpacker (ReactRailsUJS auto-mount)config/shakapacker.yml; the branch is therefore blocked on whether to add real Shakapacker config or stage a broader migration firstsaeloun/miru-webvite_rails+ SPA roothome#indexinto one global Vite entrypoint that mounts a single#react-root, so this is an app-shell case study rather than an incremental island migrationcodeforpdx/dwellingly-appreact-railswith SPA routing3.0.1not building on this macOS arm64 hostrubyforgood/demand-progressWebpacker+ ad hoc React mount2.5.1not building on this macOS arm64 hostStretch and Blocked Targets
antiwork/gumroadexercism/websiteWhale Targets
These are the high-value proof points that should come after the first wave is clearly credible.
mastodon/mastodonvite_rails+ Reactgitlabhq/gitlabhqvite_rails+ ReactInstitutional Middle Tier
These are not whales, but they are still strong proof points once the first wave is done.
thecartercenter/nemoreact-rails+shakapackerCodeminer42/cm42-centralvite_rails+ Reactnemo; draft PR #1029 is now open for the validatedprojects.indexslice with asset and request-harness notesbroadinstitute/single_cell_portal_corevite_rails+ customwindow.SCP.renderComponentbridgecm42-central; draft PR #2381 is open for the validatedstudies#usage_statsslice, and the remaining gap is Mongo-backed controller/request proofdigitalepidemiologylab/crowdbreaksWebpacker+webpacker-reactReference Repos Already On React on Rails
These are useful references. Some are also legitimate upgrade-PR candidates.
ifmeorg/ifmereact_on_rails12.0.1,webpacker5.4.4, React17justin808/ifme:codex/upgrade-react-on-rails-16is pushed and locally revalidated; upstream PR is blocked only by the project's Slack-first contribution processhoudiniproject/houdinireact_on_rails12.6.0, JS package12.2.0,webpacker5.4.4, React173.0.7is brittle on this macOS arm64 host and the patched local install was not healthy enough to run Bundleravalonmediasystem/avalonreact_on_rails14.2.1,shakapacker8.3.0, React19ifmeandhoudini, but first fix the missing pinnedactive-fedoragit revision in the baseline appsharetribe/sharetribereact_on_rails13.0.2, React16hostolab/covidlistereact_on_rails12.2.0,webpacker5.3.0, React17, Node12Known Cross-Cutting Blockers
Related Issues and PRs
react-dom/clientwarning follow-up: #3137client/package layout follow-up: #3205What Is Still Missing
nemonow has both asset and request-harness notes, but the request result is maintainability-first rather than a speedup story and it still needs a browser waterfall pass before it becomes a stronger public benchmarknemomaintainer feedback landsclient/rather than the Rails root