Five stages of incremental strangler micro frontends migration: Start with monolith, Plan and identify first slice, Build shared shell and routing layer, Carve out and deploy micro-frontend independently, Scale by repeating pattern for additional slices.

The incremental strangler micro frontends migration pattern

The strangler-fig pattern lets you migrate a monolithic frontend to micro-frontends one piece at a time, shipping features all the while - no long rewrite pause.

What is incremental strangler micro frontends migration?#

The strangler-fig pattern lets you migrate a monolithic frontend to micro-frontends incrementally by building new features in parallel, routing traffic gradually, and maintaining rollback capability. Martin Fowler's 2019 article describes how to carve a product based on what end users see. Because you replace pieces one at a time, you keep the system running.

The strangler pattern succeeds because your system keeps building and releasing during migration. Instead of a pause for a rewrite, you move incrementally. Steve Kinney's 2026 course shows how this avoids the long rewrite bunker that freezes features.

This differs from a full rewrite in a key way: you treat the monolith as the fallback. You route new features to a parallel micro-frontend. Then you gradually retire the old paths. The pattern needs three key pieces: a shared shell, a routing seam, and independent deployment. Let's see how each one works.

Why does incremental migration preserve feature velocity when rewrites freeze it?#

Incremental migration lets feature teams ship independently during the transition, avoiding the 6-18 month rewrite bunker where no new features ship. A rewrite forces you to finish the whole replacement first. This halts feature work for months and cuts revenue during the pause.

Contentsquare documented a 2021 case: a 40-person software engineer team migrated half a million lines while shipping in parallel. Because they used web components, each piece deployed independently. They released on their normal schedule. A rewrite would have frozen the product for months.

The business case is strong: parallel shipping protects revenue and user experience. Because teams keep momentum, they stay close to user feedback. So when migration hits a problem, they can fix it fast. A rewrite forces a choice: stop all features for months or keep the old code.

Show data table
Contentsquare's incremental migration: 40-person team migrated half-million lines of code while shipping in parallel, 2021.
Item Value
Half-million line AngularJS/Angular application half million
Frontend developer team 40
Migration approach single repo for all micro-frontends

Incremental migration succeeds at scale: a large team and codebase migrated in parallel while shipping features.

Figure Contentsquare's incremental migration: 40-person team migrated half-million lines of code while shipping in parallel, 2021. Contentsquare Engineering case study, 2021. Modelled, not measured from our own work.

When not to use incremental strangler micro frontends migration#

Incremental migration carries overhead (dual frontend maintenance, state synchronization, routing logic) that a clean rewrite avoids; use incremental only when the rewrite pause is unacceptable. When should you pursue a full rewrite instead? A full rewrite wins if your monolith is unmaintainable, if your teams already work in isolated domains with zero shared state, or if you can afford the delivery pause.

Microsoft Azure's 2026 documentation says when the strangler pattern makes sense. If your monolith is unmaintainable AND you can halt features, a rewrite may be faster. But the strangler works best when you need to keep shipping during the migration.

Martin Fowler's 2019 guidance is simple: carve by business function, not by technical layer. So if your monolith has clear domain lines and teams already own those domains, incremental migration will work. However, if your monolith mixes technical concerns with no clear slice, a from-scratch rewrite might move faster.

How do you identify the first slice to carve out?#

Your first slice should be a feature small enough to ship in one or two sprints, owned by a single team, with clear business value and minimal shared state dependencies. Pick a high-traffic feature the team owns fully. Avoid deeply-nested utilities only other code depends on.

Martin Fowler's 2019 article is clear: form teams around business slices, not technical layers. Why? Because if you slice by layer (all API calls in one micro-frontend, all UI state in another), you create tight coupling. And tight coupling defeats the whole point of independent work.

Microsoft Azure's guidance adds this: start with a boundary that minimizes shared state. A good slice is something users use often (so you see real traffic). The team should own it fully (checkout, profile, catalog, search). And it should not depend on everything else in the monolith. Avoid utilities used everywhere (form fields, date pickers) or features tied to many systems (authentication).

The slice should finish in one or two sprints. Because this teaches your team how to manage two frontends without committing to massive change. Short timelines force you to find the seams between systems. They also let you course-correct if the architecture does not work. For instance, if the first slice takes three months, you learn little about scaling. But if it takes six weeks, you have real data about whether teams can own multiple frontends.

Identifying a low-risk first micro-frontend slice: ranked selection criteria. Martin Fowler, 2019 strangler fig pattern. Microsoft Azure strangler-fig documentation, 2026.

CriterionWhat it meansWhy it matters
Team ownershipOne team clearly owns this code and feature.Clarity on who maintains the slice avoids handoff delays and version chaos.
Low dependenciesThe slice imports little from the monolith; little imports from it.Independent versions and safe deployment are only possible when coupling is loose.
High trafficUsers encounter this slice frequently.Visible slices prove the pattern works faster and motivate the next one.
Short timelineThe work can finish in weeks, not months.Early wins keep momentum; long slices prove nothing while tying up a team.
Try it
Codebase scale
Frontend team size
Slice type

Moderate viability

This slice is a candidate, but one factor is worth attention. Consider addressing team ownership or dependency isolation before carving it out.

Estimated effort: 4-8 weeks, with upfront refactoring

First-slice selection criteria (ranked)
CriterionWhat it meansWhy it matters
Team ownershipOne team clearly owns this code and feature.Clarity on who maintains the slice avoids handoff delays and version chaos.
Low dependenciesThe slice imports little from the monolith; little imports from it.Independent versions and safe deployment are only possible when coupling is loose.
High trafficUsers encounter this slice frequently.Visible slices prove the pattern works faster and motivate the next one.
Short timelineThe work can finish in weeks, not months.Early wins keep momentum; long slices prove nothing while tying up a team.

This picker scores your slice against the ranked criteria from Martin Fowler and Microsoft Azure guidance. Adjust the answers to match your codebase and see which first slices rank highest.

Test whether your slice candidate fits the first-slice profile. Adjust codebase scale, team size, and slice type to get a viability recommendation. Modelled, not measured.

How do you build the shared shell and routing seam?#

A shared shell (static layout, navigation, authentication context) routes traffic to old and new frontends by path; single-spa or custom routing orchestrates the handoff. The shared shell is where the strangler pattern lives: old paths route to the monolith, new paths route to the micro-frontend, and both share auth context without code duplication.

Vercel's 2026 guide says the shared shell is the glue. It handles navigation, routing, auth tokens, and feature flags. Because both frontends render in the shell's container, they inherit the same auth and navigation bar.

Single-spa provides client-side routing for independently deployed micro-frontends. You register each frontend as an app tied to routes. When users navigate to /new-feature/, the router mounts the new code and unmounts the old. So the swap can be instant or gradual (for example, canary deploys to a small percent of traffic first).

The routing seam is the contract between frontends. If the monolith serves /checkout and the new code serves /profile, the router knows which to use. Because they are separate, rollback is easy. If the new frontend crashes, the router switches back to the old code.

DiagramStrangler routing topology: shared shell orchestrates traffic by path, routing old paths to monolith and new paths to micro-frontends.

How do you synchronize shared state and authentication across frontends?#

Shared state at the routing seam is the hardest part of incremental migration: user session, feature flags, and business data must stay in sync across two independently-deployed frontends. Shared state failures cause silent data loss and inconsistent UX. Use shadow writes (new frontend logs to the same backend) and validation reads (old frontend checks new state) to detect sync failures early.

Steve Kinney's 2026 course identifies data migration as the hardest part of incremental adoption. The problem is that the old frontend and the new micro-frontend both hold copies of the same state. They can diverge. If the monolith updates a user's preferences and the new micro-frontend doesn't know about it, the user sees inconsistent experience. They change their timezone in the old app, navigate to the new app, and their timezone is still the old value.

The shadow-write pattern prevents this. The new micro-frontend writes to the same backend as the monolith and writes to its own local state. Then it verifies that the backend persisted it. The monolith validates backend state before using it locally, protecting against stale in-memory caches. This dance adds overhead but catches sync failures before they cascade into corrupted user data.

Microsoft Azure's strangler-fig documentation (2026) warns that state synchronization is where most incremental migrations fail. The best practice is to store all state on the backend. Use the backend as the source of truth. Treat frontend caches as read-through layers. Each frontend refetches state when it activates, verifying consistency.

  1. New micro-frontend writes to shared backend (shadow write)

  2. New micro-frontend validates backend persisted the write

  3. Old monolith reads state from backend before using it locally

  4. Sync failures are logged and caught before users see inconsistency

What deployment and pipeline changes are required for independent micro-frontends?#

Independent micro-frontends require independent CI/CD pipelines per frontend; your deployment orchestrator must coordinate versioning, rollback, and partial failures. Module Federation (Webpack 5+) enables runtime code sharing without pre-coordination. Single-spa provides client-side routing for independently deployed micro-frontends.

According to Webpack's concepts documentation (2026), Module Federation lets the new micro-frontend consume shared modules (React, lodash, your design system) from the monolith's bundle. So the new code avoids duplicate downloads and bundle bloat. Each micro-frontend builds and deploys independently. Then the shared shell's CDN manifest tells it which versions are live.

Single-spa's documentation shows how to register applications and manage their lifecycle. When you deploy a new version, you update a manifest file that the shared shell reads. Because the shell fetches the new version from the CDN, it can activate it on the next navigation. Old users stay on old versions until their next navigation. Meanwhile, new users get the new version immediately.

The deployment system must handle versioning, rollback, and coordinated deploys. If the new micro-frontend crashes, you roll it back without touching the monolith. When both ship at the same time and a state sync breaks, you roll back both or roll back only the micro-frontend.

What does a minimal strangler-fig deployment look like?#

A strangler setup starts with a shared shell that routes paths: fetch the micro-frontend manifest, load the remote module, mount it in the shell, and fall back to the monolith. A three-step minimal example: (1) load the new micro-frontend's bootstrap from a CDN, (2) call single-spa.registerApplication to claim the /new-feature/* path, (3) call singleSpa.start() to activate routing.

javascript
// 1. Fetch the manifest and load the micro-frontend's entry point
const manifest = await fetch('https://cdn.example.com/micro-frontend-manifest.json').then(r => r.json());
const microFrontendUrl = manifest['micro-frontend'].bootstrap;

// 2. Register the micro-frontend with single-spa
singleSpa.registerApplication({
  name: '@example/micro-frontend',
  app: () => System.import(microFrontendUrl),
  activeWhen: '/new-feature'
});

// 3. Start routing
singleSpa.start();

This minimal example assumes the shared shell already handles navigation and auth context. The micro-frontend's entry point (the bootstrap script) mounts itself inside a DOM container that the shell provides. If the micro-frontend fails to load, single-spa keeps the shell running. The old monolith still handles other routes.

For a production deployment, add error boundaries (a fallback UI if the micro-frontend crashes). Add a health check before activating the new route. Test new versions with canary deploys rolled out to a small traffic percentage first.

How should teams be structured during incremental migration?#

During incremental migration, one team owns the monolithic frontend and one team owns the new micro-frontend; both teams must own their deployment and rollback. So teams need autonomy: each frontend team controls its own CI/CD, versioning, and rollback. Meanwhile, the shared shell team owns the routing logic and enforces the interface contract.

Martin Fowler's 2019 guidance is clear: teams need to be formed around vertical slices of business functionality. Because each team owns its own deployment, this principle becomes critical during migration. The monolith team knows the old codebase. They release on their normal schedule and focus on shipping features in the untouched routes. Meanwhile, the new micro-frontend team owns the new routes. Because they experiment with new architecture choices (a different framework, a new build tool), they release on their own cadence.

The shared shell team is smaller and holds a different responsibility. Since they own the routing logic and maintain the manifest, they ensure the interface contract stays stable. If the routing breaks, both teams are blocked. However, if a micro-frontend breaks, only its routes are affected. This separation of concerns lets teams move independently.

Finally, cross-team dependencies are minimized through the interface contract. The shared shell defines the authentication context shape, the feature flag format, and the event bus that frontends use to communicate. As long as each team respects the contract, they can deploy on their own schedule.

How do you handle rollback when partial migration fails?#

Rollback during incremental migration is faster than rewrite because you simply re-route the /new-feature/* paths back to the monolith; the monolith still serves all traffic. Plan for three rollback scenarios: the micro-frontend crashes (re-route to old code), shared state gets out of sync (shadow writes detect this), or the monolith breaks while new code ships (run the old build).

If the new micro-frontend crashes in production, the shared shell detects the error and re-routes to the monolith in seconds. Users on the old route never notice. Users who navigated to the new route see a fallback message ("this feature is temporarily unavailable") and can retry. The monolith is always running as a fallback.

If shared state gets out of sync, the shadow-write validation catches it before users see the inconsistency. The error log shows which state diverged. You can roll back one or both frontends until the sync is fixed. Because you are not dependent on the new micro-frontend being perfect, you have time to diagnose the failure.

Microsoft Azure's strangler-fig documentation (2026) describes the "transform-coexist-eliminate" phases: transform the monolith piece by piece, coexist with the replacement while both are live, and eliminate the old code only after the replacement is proven. Rollback is built into this model. If the replacement fails, you simply stay in coexist mode longer or roll back entirely.

Steve Kinney's 2026 course emphasizes that rollback is the safety valve of incremental migration. If the pattern does not work for your organization, if the micro-frontend introduces more problems than it solves, you stop the migration and keep the monolith. You have learned what does not work without the sunk cost of a full rewrite.

  1. Micro-frontend crashes

  2. State synchronization breaks

  3. Monolith breaks during deployment

Where do you go next with incremental strangler migration?#

Start by deciding whether incremental migration fits your situation; if it does, pick your first slice, wire the routing seam, and launch independent CI/CD. The strangler pattern works: incremental adoption avoids the rewrite pause and teaches your organization how micro-frontends scale.

Take three practical steps to move forward. First, audit your codebase for slice candidates: look for features users care about, that one team owns, with low dependencies. Second, wire a shared shell: build or adopt a routing solution (single-spa, custom routing, or iframe isolation). Third, set up independent CI/CD: each frontend gets its own pipeline, its own deploy schedule, and its own rollback plan.

Contentsquare's documented migration of half a million lines of code shows the pattern scales. Because their team kept shipping while migrating, they maintained morale and revenue. Martin Fowler's foundational guidance on slicing by business functionality gives you the decision framework. Steve Kinney's course on strangler-fig patterns teaches the implementation details. Both sources show that organizational alignment matters as much as technical architecture.

For deeper technical patterns, read our guide to module federation integration strategies to understand how to share code across micro-frontends. For the broader architectural question of whether micro-frontends make sense for your problem, start with our post on when micro-frontend complexity is worth it. When your migration needs support, our scale-optimize service works with teams managing complex, partially-migrated systems. Our frontend hiring service augments your team with architects experienced in incremental migrations.

The strangler pattern is proven, and real teams use it every day. Contentsquare used it, as do other large teams. Because it works, you can use it too. Start by picking your first slice: one slice, one team, two or three sprints. Then you will know if your team can handle two frontends at once. If it works, pick the next slice. If it does not work, you learn fast and adjust the plan. There is no long rewrite, no big bet on a new architecture that may fail. Just one slice at a time: build, learn, and move on to the next. The strangler pattern is how incremental migration should work.

Questions this post answers

How do incremental strangler micro frontends migration avoid the rewrite pause that kills product velocity?
Incremental migration lets feature teams ship independently during the transition, avoiding the 6-18 month rewrite bunker where no new features ship. A rewrite forces you to finish the whole replacement first.
When should you carve out your first slice during incremental migration?
Your first slice should be a feature small enough to ship in one or two sprints, owned by a single team, with clear business value and minimal shared state dependencies. Pick a high-traffic feature the team owns fully. Avoid deeply-nested utilities only other code depends on.
What happens if shared state gets out of sync between the monolith and a new micro-frontend?
Use shadow writes (new frontend logs to the same backend) and validation reads (old frontend checks new state) to detect sync failures early. If shared state gets out of sync, the shadow-write validation catches it before users see the inconsistency.

Keep reading