In the software world, the “Ship of Theseus” paradox is a daily reality. We replace parts of a system until, eventually, none of the original code remains. But usually, the industry moves toward the “shiny new thing.”
At work, we did something that might sound like heresy to some: we migrated our core legacy React applications to Angular.
This wasn’t a decision made out of fanboyism. It was a strategic move driven by the need for governance, stability, and long-term maintainability in a high-stakes FinTech environment. I’ll explain the architectural “why” and the pragmatic “how” of moving against the grain.
The Strategic “Why”
React is a library; Angular is a platform. For a small startup, React’s flexibility is a superpower. But for an enterprise processing millions of transactions, that same flexibility can become a liability.
1. Strict Governance
In the React ecosystem, there are ten ways to do everything: state management (Redux, MobX, Recoil, Context), routing, form handling, and styling. As our team grew, we found ourselves spending more time debating how to build a feature than actually building it.
Angular’s “opinionated” nature solved this. By providing a standard way to handle dependency injection, routing, and forms, Angular allowed us to move engineers between teams with zero friction. Every project looked and felt the same.
2. Dependency Management
React relies on a fragmented ecosystem of third-party libraries. To build a production-ready app, you might need 20 different packages from 20 different maintainers. If one of those packages becomes deprecated or introduces a breaking change, you are in “dependency hell.”
Angular’s “batteries-included” approach means that the core team maintains the router, the HTTP client, the forms library, and the CLI. When you update Angular, everything updates together. This stability is crucial for a FinTech platform where security and reliability are non-negotiable.
3. Performance and Scalability
While React is fast, we found that Angular’s Ahead-of-Time (AoT) compilation and its new Signals-based reactivity model (which I’ve discussed in my post on Angular Signals and Control Theory) provided a more predictable performance profile for our complex, data-heavy dashboards.
The Pragmatic “How”
We couldn’t just stop the world for six months to rewrite everything. We had to perform a “Ship of Theseus” migration, replacing the ship while it was still at sea.
1. The Nx Monorepo
The first step was consolidating our fragmented repositories into an Nx Monorepo. This allowed us to share code between the old React apps and the new Angular apps during the transition. It also reduced our CI/CD build times by 50% through intelligent caching.
2. The Design System Bridge
We built an internal Angular-based design system (see my post on The Cost of Consistency). To maintain UI consistency during the migration, we used Web Components to bridge the gap, allowing us to use the same UI elements in both React and Angular.
3. Incremental Migration
We didn’t migrate page-by-page; we migrated feature-by-feature. We used a “Strangler Fig” pattern, where new features were built in Angular and served alongside the legacy React code using a reverse proxy. Over time, the Angular “fig” grew until it completely replaced the React “tree.”
The Outcomes
The results were measurable and significant:
- 40% Faster Delivery: Thanks to the standardized framework and design system.
- 50% Faster CI/CD: Through Nx monorepo optimization.
- 15 to 4 Minute Deployments: By optimizing our Docker-based pipelines.
- 100% Feature Parity: We delivered the migration with zero downtime and zero reported regressions.
Conclusion: Choosing the Right Tool for the Job
The “React vs. Angular” debate is often framed as a matter of taste. But for us, it was a matter of engineering strategy. By choosing a platform that prioritized governance and stability, we were able to scale our frontend organization from 1 to 15 engineers while maintaining a 100% retention rate.
Sometimes, the “Ship of Theseus” needs a new hull, not just a new coat of paint.
Further Reading & References
- “Angular: Up and Running” by Shyam Seshadri: A great guide for those transitioning from other frameworks.
- Nx Monorepo Documentation: The tool that made our migration possible.
- The Cost of Consistency: When Your Design System Becomes a Bottleneck: Lessons learned from building our Angular design system.
- The ‘Signal’ and the ‘Noise’: Applying Control Theory to Angular’s New Reactivity Model: A deep dive into Angular’s performance model.
- “Micro Frontends in Action” by Michael Geers: Techniques for running multiple frameworks side-by-side.
Omid Farhang