Coding agents have made generating migration code remarkably fast.
The bottleneck now is proving that it behaves exactly like the mature production system it's replacing.
For platform teams modernizing large Ruby on Rails applications, the challenge is no longer translating Ruby into TypeScript. It's deciding where to start, validating behavioral parity, and reducing migration risk without breaking years of accumulated business logic.
I recently spoke with a tech lead responsible for a large Rails monolith. Their biggest challenge wasn't generating Node.js code. It was knowing where to start and proving that a migrated service behaved identically by comparing API responses, SQL queries, Redis interactions, and production traffic during gradual rollouts.
That conversation inspired this case study.
Instead of asking "How do we migrate the monolith?", we asked:
"Where should we start so we can verify quickly, build confidence, and make every migration after that faster?"
To answer that, we analyzed OpenProject, a large production Ruby on Rails application, using Codemod's Ruby Migration Assessment Bundle. The repository is real. The migration is hypothetical. The assessment is real.
In under a minute, anyone can run the same assessment against their own Rails repository. It inventories the codebase, maps dependencies, surfaces architectural risks, and highlights candidate starting points so engineering teams can prioritize what to migrate first and what to harden beforehand.
OpenProject is representative of the kind of legacy Ruby on Rails monolith many platform teams are modernizing today: a mature production application with multiple feature engines, rich ActiveRecord models, background jobs, and years of accumulated business logic. At first glance, it looks ready to be decomposed into services one engine at a time.
Repository analysis tells a different story.
We started by inventorying the codebase, not to count files, but to understand how responsibilities are distributed, where dependencies accumulate, and which domains are actually safe to extract.


A few things stand out immediately.
The core of the application lives in app/models, with 110 ActiveRecord models and 383 associations. Around it are feature engines with very different architectural shapes. modules/meeting has a large controller surface and extensive request tests. modules/storages contains only four models but thirty-seven service objects. modules/budgets, by comparison, is remarkably small.
That's exactly why counting models isn't enough.
If you're planning a migration, the question isn't "Which module has the fewest files?" It's "Which module has the fewest surprises?"
To answer that, we need more than an inventory.
We need to understand how those domains interact.


Every signal in this dashboard answers the same question: "How expensive will it be to prove this migration is correct?" Request-test coverage estimates how much behavior is already validated. ActiveRecord complexity hints at hidden business logic. Cross-domain dependencies expose where seemingly isolated services still share data or behavior. None of these decide the migration for you, but together they help estimate the verification effort before a single line of TypeScript is written.
Some of the headline findings include:
- 182 ActiveRecord models
- 672 associations
- 290 callbacks
- 1,070 raw SQL findings
- 3,262 STI findings
- 51,564 cross-domain dependency edges
None of these numbers are goals or scores. They're architectural signals.
A callback count hints at hidden business logic that may not be obvious from the controller or service layer. Raw SQL often points to behavior that won't be captured by ORM migrations alone. Shared tables increase the likelihood that two services will need to evolve together. Dependency edges reveal how often seemingly independent domains still rely on one another.
None of these metrics make a migration impossible. They simply explain where verification is likely to become more expensive.
The first migration isn't about moving the most code.
It's about reducing uncertainty.
You want to prove that Rails and TypeScript can run side by side, that API behavior can be validated, that deployments can be decoupled, and that production traffic can shift safely.
Once you've proven that, every migration after the first gets faster.
That's exactly what the assessment is designed to support. Rather than ranking domains by size alone, it combines signals such as dependency density, ActiveRecord complexity, request-test coverage, service density, and external integrations. Together, these give platform teams a structured way to compare extraction candidates and discuss where a first migration is likely to require less verification effort.


Several domains emerged as reasonable candidates for a first migration, but they weren't equal.
Some quickly ruled themselves out. modules/storages, for example, contains relatively few models, yet repository analysis shows one of the highest dependency counts in the application. It also relies heavily on service objects and external integrations. Despite its size, migrating it would likely require redesigning application boundaries and operational behavior at the same time.
The core platform is an even harder place to begin. Models such as WorkPackage, Project, and Principal sit near the center of the dependency graph. Changes there would ripple across much of the application, dramatically increasing the amount of verification needed before shipping.
Among the smaller engines, modules/budgets stood out for a different reason. It combines several characteristics that engineering teams often look for when evaluating an initial extraction candidate: a clear engine boundary, relatively limited coupling to central platform models, a manageable API surface, fewer external integrations, and a smaller background job footprint.


None of those characteristics guarantee that Budgets should be migrated first. Team ownership, roadmap priorities, operational constraints, and domain expertise may point to a different starting point. Repository analysis cannot make that decision.
What it can do is narrow the search. Instead of debating dozens of possible starting points, engineering teams can focus their discussions on a much smaller set of candidates that appear less risky from an architectural perspective.
More importantly, the assessment surfaces the work that is likely to reduce verification effort before any migration begins.


Notice that almost none of the suggested follow-up work involves writing TypeScript.
In OpenProject, repository analysis highlighted opportunities such as extending the assessment with miners for Grape (API::V3) and Roar representers, expanding request-test coverage around candidate domains, reviewing callback-heavy models, and understanding shared database ownership. Some of these come directly from repository findings, while others are engineering follow-ups suggested by those findings.
That's a pattern we've seen repeatedly. The highest leverage work in a migration often happens before the migration starts, because every improvement in observability, validation, or architectural understanding reduces uncertainty during implementation.
Everything you've seen so far was generated automatically from repository analysis.
Instead of manually tracing dependencies or counting callbacks, we ran Codemod's Ruby Migration Assessment Bundle. It contains a collection of focused mining codemods, each analyzing one aspect of a Rails application, from ActiveRecord models and callbacks to request tests, background jobs, and cross-domain dependencies.
Each miner produces structured findings, which Codemod Insights combines into the dashboards shown throughout this article.
For OpenProject, we started with the generic assessment bundle.


The bundle includes sixteen mining codemods:
Mining Codemod | Purpose |
| Inventory ActiveRecord models |
| Discover model relationships and coupling |
| Find lifecycle callbacks and hidden business logic |
| Inventory model validations |
| Detect Single Table Inheritance hierarchies |
| Surface handwritten SQL |
| Identify transactional boundaries |
| Inventory Rails controller endpoints |
| Discover serializers and response models |
| Inventory service-layer business logic |
| Analyze asynchronous workloads |
| Find Redis usage and distributed coordination |
| Discover third-party dependencies |
| Measure request-level validation coverage |
| Map dependencies between application domains |
| Identify shared database ownership |
The interesting part isn't that there are sixteen miners.
It's that they work together.
A callback inventory becomes much more useful when you combine it with transaction analysis. Dependency graphs become more actionable when overlaid with request-test coverage. Shared-table analysis explains why an engine that looks isolated on disk may still be a poor candidate for extraction.
The dashboard is simply the result of combining those perspectives.
The generic bundle gets you most of the way there. From there, every organization can teach it about its own architecture.
In OpenProject's case, that means adding miners for Grape (API::V3), Roar representers, and contracts, patterns that aren't common across every Rails application.
That's the real value of the Codemod platform. You start with a reusable assessment, then extend it with codemods that understand your codebase, turning Codemod Insights into a living architectural knowledge base.
Migrating a legacy Ruby on Rails application isn't just about generating code. It's about understanding the architecture you're changing.
In this case study, a generic Rails → TypeScript assessment was enough to inventory the OpenProject codebase, identify migration hotspots, compare extraction candidates, and recommend a low-risk starting point. It also highlighted where deeper, organization-specific analysis would help, for example, with Grape (API::V3), Roar representers, and contracts.
That's the real value of repository mining. You start with a reusable assessment, then extend it with codemods that understand your architecture, whether that's payment flows in fintech, PHI handling in healthcare, or checkout systems in e-commerce.
The result isn't a fully automated migration plan. It's a repeatable assessment process. By turning repository structure into concrete architectural evidence, platform teams can spend less time debating where to start and more time validating the migrations that matter.


Repository mining isn't just about reducing the risk of the first migration.
It's about choosing a migration that maximizes learning.
The first successful migration becomes much more than a rewritten service. It produces new validation techniques, rollout patterns, engineering playbooks, reusable codemods, and agent skills that can be applied to every migration that follows.
As teams migrate additional services, the migration platform itself evolves. Repetitive transformations become deterministic codemods. Repository-specific patterns become reusable mining rules. Proven workflows become agent skills that other teams can reuse instead of rediscovering the same solutions.
Over time, increasingly large portions of the migration can be automated with compiler-aware, deterministic transformations, while AI focuses on the remaining work that still requires engineering judgment. Every successful migration expands the toolkit available to the next team.
That's why the first migration isn't about moving the most code. It's about building momentum. Every iteration reduces uncertainty, captures organizational knowledge, and makes the next migration faster, easier, and safer.
The assessment in this article isn't specific to OpenProject. You can run the same Ruby Migration Assessment Bundle against your own Ruby on Rails repository and generate migration readiness dashboards, architectural insights, and candidate starting points in under a minute.
Need something more tailored?
We also build repository-specific assessment bundles that understand your architecture, frameworks, and internal patterns. And if you'd rather not own the migration yourself, our Codemod Certified experts can embed with your team and take end-to-end ownership of the migration, from assessment and planning through implementation and rollout. Contact us to learn more.