Incremental React migration
Professional work at Watch Portfolio Management · 2018–2024
Context
At Watch Portfolio Management, I led the move of internal business applications from jQuery and server-rendered views to React and TypeScript. The work took place within my 2018–2024 role, alongside ongoing development of the existing systems.
The problem
Applications had their own UI patterns, with little shared component reuse. A new form or screen often meant writing another version of behaviour that already existed elsewhere. Frontend changes were difficult to carry between applications.
What needed to change
As interfaces became more complex, scattered JavaScript and separate UI conventions became harder to maintain. The challenge was to introduce a shared frontend foundation while keeping the applications usable.
What I designed
I led an incremental migration with new React routes alongside legacy pages. A shared component library provided reusable buttons, forms, modals and layout primitives, supported by design tokens. The existing C# .NET Core API remained the source of truth, with a TypeScript client generated from OpenAPI. This gave the frontend a clearer contract without requiring the backend and every screen to be replaced together.
Tradeoffs considered
- Building shared components took time that could otherwise have gone into individual features. The benefit was a foundation the applications could reuse.
- Migrating route by route meant accepting a temporary mix of old and new interfaces. It kept the scope of each change manageable while the business continued to use the software.
- Generated types helped identify contract mismatches during development. They still needed to be supported by checks of actual runtime behaviour.
Evidence and outcomes
- Shared UI foundation
- A component library reused across internal applications and adopted beyond the original migration work.
- Incremental delivery
- React routes introduced alongside legacy pages, with the existing API retained.
- Clearer contracts
- A generated TypeScript client connecting frontend code to the OpenAPI definition.
Lessons learned
- Choose migration boundaries that fit the existing application. A route can be a useful unit of change when users need the rest of the system to keep working.
- Invest in shared components where the repetition is real. The value comes from reuse in working applications.
- Treat type generation as one part of validation. A typed contract does not replace testing the behaviour people depend on.
This account focuses on architecture and delivery choices. Internal measurements, test results and proprietary implementation details are not published.