2025.12.08 · 8 min read · react

Migrating AngularJS to React without a rewrite freeze

The big-bang rewrite is the project that's always 80% done. Here's how to migrate a legacy AngularJS app to React while the product keeps shipping.

Ahmed El Banna
Ahmed El Banna
Technical Leader · Full-Stack Engineer

Every team carrying a large AngularJS app eventually faces the same temptation: stop the world, rewrite everything in React, ship the shiny new version in six months. That project is almost always still "80% done" eighteen months later. There's a better way.

Strangle, don't rewrite

The Strangler Fig pattern is the whole strategy: wrap the legacy app, route new and migrated features through React, and let the old code base shrink one route at a time. The product never stops shipping because at no point is the app broken.

A migration nobody can feel is a migration that survives the next quarterly roadmap review.

Make the two frameworks coexist

The mechanical core is mounting React components inside AngularJS and sharing state across the boundary. A thin adapter directive lets an Angular template render a React tree:

react-bridge.js
angular.module("app").directive("reactBridge", () => ({
  restrict: "E",
  scope: { component: "<", props: "<" },
  link(scope, element) {
    const render = () =>
      ReactDOM.render(
        React.createElement(scope.component, scope.props),
        element[0]
      );
    scope.$watch("props", render, true);
    scope.$on("$destroy", () => ReactDOM.unmountComponentAtNode(element[0]));
  },
}));

New features get built in React from day one. Existing screens migrate when they're touched anyway — a bug fix or a redesign becomes the moment to port that route.

The leadership half

The technical pattern is the easy part. The hard part is holding the line on three commitments:

Done this way, the migration finishes not with a dramatic cutover but with a quiet commit that deletes the last Angular module — and nobody outside the team ever noticed the ground move.