The strangler fig pattern applied to frontends
The strangler fig pattern replaces a legacy system piece by piece while it keeps running. This guide shows how it works for a frontend, where the seam goes and what a real sequence looks like.
The idea in one paragraph
A strangler fig grows around a host tree and, over time, takes its place. Martin Fowler used the image to describe a way of replacing legacy systems: build the new system around the edges of the old one, route more and more work to the new parts, and remove the old parts as they become unused. At no point is there a single switch-over day.
For a frontend this means users keep one product, one URL and one login while the code behind each screen changes.
The key decision: where the seam goes
The pattern needs a place where a request can be sent to old code or to new code. In a frontend there are three practical places.
| Seam | How it works | Fits when |
|---|---|---|
| At the edge | A reverse proxy or the web server sends some URL paths to the new app and the rest to the old one | Old and new are separate applications, or the old app is server-rendered |
| In the shell | One application hosts both frameworks, and the router decides which one renders each route | AngularJS to Angular with the official upgrade tooling |
| Inside the page | New components are mounted into old pages, often as custom elements | Pages with a lot of jQuery, or legacy frameworks with no bridge |
How to choose the seam
- If the old app is AngularJS and the target is Angular, the shell-level seam is usually the better fit, because both sides can share services directly. The details are in How to migrate AngularJS to Angular without downtime.
- If the two sides cannot run in the same page, use the edge. Navigation between old and new is then a full page load, so pick boundaries where users rarely jump back and forth.
- If the old pages are server-rendered with scripts on top, start inside the page and move to whole pages later. The jQuery migration guide follows this route.
What old and new must share
The pattern fails when users can see the seam. Four things need to be shared from the first day:
- Session. One login. Both sides read the same token or cookie and react to expiry the same way.
- Navigation. One menu and one set of URLs. Deep links and the back button behave as before.
- Look. Shared styles or design tokens, so a migrated screen does not look like a different product.
- Data layer. One source for the current user, permissions and settings. Two copies of the same state produce bugs that are hard to reproduce.
An example sequence
Take an order management app with five areas: dashboard, orders, customers, reports and settings.
- Inventory and seam. List the screens of each area. Choose the shell-level seam. Decide that reports is the pilot, because it is read-only and isolated.
- Build the shell. The new application starts first and loads the legacy app inside it. Unknown routes fall through to the legacy router. Users notice nothing.
- Share the plumbing. Move authentication and the HTTP layer to the new side and expose them to the legacy side.
- Strangle the first route. Rebuild the reports list in the new framework. Put the route behind a switch. Release it to internal users, then to everyone.
- Delete. Once reports is stable, remove its legacy code. The old app is now smaller.
- Repeat by area. Settings next, then customers. Each area follows the same steps: rebuild, switch, observe, delete.
- Take the centre. Orders is the busiest and most complex area. It goes late, when the patterns are proven and the team is fast.
- Replace the frame. Move the navigation, the layout and the login to the new side.
- Remove the host. No route reaches the legacy app. Delete it, the old router and the bridge between the two.
Each numbered step is released on its own. Feature work continues in every area that is not being migrated at that moment.
Pitfalls
- Strangling by technical layer. Migrating "all the services" or "all the forms" delivers nothing users can see. Strangle by route or by business area.
- Never deleting. If the old version of a screen stays after the new one is live, the tree never dies and you maintain both.
- A leaky seam. Old code that reaches into new components, or the reverse, through global variables. Keep the contact surface small and explicit.
- No end condition. Define at the start what "the host is gone" means, and plan the cleanup.
When the pattern is the wrong tool
For a small app that one developer can rebuild in a few weeks, the seam costs more than it saves. A direct rewrite is simpler. The comparison is in Rewrite, hybrid or micro-frontends.
More in this section
- Feature flags and route switches in an incremental migration
- Leaving AngularJS: Angular or React?
- Migrating a jQuery-heavy app to a component framework
- Migrating Backbone, Knockout and old Ember applications
Planning a migration or a micro-frontend platform?
In a 20-minute call you describe your situation and I tell you how I'd approach it. If it isn't worth doing yet, I'll say so.
Message me on LinkedIn