Blog / Architecture
Architecture

The Strangler Fig Pattern: Migrating Legacy Systems Incrementally

Implementing the strangler fig pattern for legacy migration with request routing, data synchronization, feature parity verification, and a realistic migration timeline.

Akhil Sharma

Akhil Sharma

March 26, 2026

10 min read

The Strangler Fig Pattern: Migrating Legacy Systems Incrementally

The strangler fig tree grows around an existing tree, gradually replacing it while using it for structural support. Eventually, the host tree dies and the fig stands on its own. This is the best metaphor for migrating legacy systems — you build the replacement around the existing system, incrementally routing traffic from old to new, until the legacy system can be decommissioned.

The alternative — a full rewrite that launches on a single cutover date — fails more often than it succeeds. Big-bang rewrites take years, miss edge cases, and collapse under the weight of requirements that were "obvious" in the old system but undocumented.

The Pattern

Step 1: Install the Proxy

Before writing any new code, insert a reverse proxy in front of the legacy system. Initially, it passes all traffic through unchanged. This is the foundation — every subsequent migration step is a routing change in the proxy.

nginx

Key principle: The proxy addition should be invisible to users. Deploy it, verify that all traffic flows correctly, and only then start migrating routes.

Step 2: Choose What to Migrate First

Not all features are equal. Pick the first migration target based on:

  1. Low risk, high learning. A read-only endpoint or a simple CRUD feature teaches you the migration process without risking critical business logic.
  2. Well-understood behavior. You need to know exactly what the legacy system does. If the behavior is undocumented and full of edge cases, save it for later.
  3. Minimal data dependencies. Features that read from a single database table are easier than features that join across 10 tables.
  4. Clear boundaries. A self-contained feature (user profile management) is easier to extract than one that's deeply intertwined with everything else (order processing).

A practical first migration target: user authentication, user profile endpoints, or a standalone reporting feature.

Step 3: Data Synchronization

The legacy and new systems need access to the same data during the migration period. There are several approaches:

Shared Database (simplest)

Both systems read from the same database. The new system uses the legacy schema.

Advantage: No data sync needed. Both systems see the same data instantly.

Advanced System Design Cohort

We build this end-to-end in the cohort.

Live sessions, real systems, your questions answered in real time. Next cohort starts 2nd July 2026 — 20 seats.

Reserve your spot →

Disadvantage: The new system is constrained by the legacy schema. You're building new code on old data models. Acceptable for the migration period, but plan to migrate the schema after the legacy system is gone.

Change Data Capture (CDC)

The legacy database's changes are streamed to the new system's database. Both databases stay in sync with minimal latency.

python

Advantage: New system has its own schema. Data models can evolve independently.

Disadvantage: CDC adds latency (100-500ms) and operational complexity (Debezium, Kafka). Bidirectional sync (if both systems write) is significantly more complex.

Dual Writes (use with caution)

The new system writes to both the new and legacy databases. This keeps legacy data fresh for features that haven't been migrated yet.

python

Warning: Dual writes are fragile. If one write succeeds and the other fails, databases diverge. Use an outbox pattern or accept eventual consistency. Only use dual writes for the migration period — remove them as soon as the legacy system no longer reads the data.

Step 4: Feature Parity Verification

Before routing production traffic to the new system, verify that it produces the same results as the legacy system. Run both in parallel and compare outputs.

python

Run shadow testing for 1-2 weeks. Investigate every mismatch. Common causes: date formatting differences, field ordering in JSON, rounding differences, and undocumented legacy behaviors.

Step 5: Gradual Traffic Migration

Once shadow testing shows < 0.1% mismatch rate, start routing real traffic:

Use the proxy for traffic splitting:

nginx

Realistic Migration Timeline

A medium-sized legacy system migration (20-30 features, 50K lines of legacy code):

This is ambitious. Most large migrations take 12-24 months. The key is continuous progress — shipping migrated features every 2-3 weeks keeps momentum and shows stakeholders that the migration is working.

Common Mistakes

1. Trying to improve while migrating. Resist the urge to redesign features during migration. First, achieve parity. Then improve. Combining migration with enhancement makes both harder and doubles the risk.

2. No rollback plan. Every routing change should be reversible. If the new system has a bug, flip the proxy back to legacy within minutes. Keep the legacy system running and maintained until you're fully confident.

3. Underestimating edge cases. Legacy systems accumulate years of special cases, workarounds, and undocumented behaviors. Budget 30-40% of your migration time for discovering and handling these.

4. Stopping too early. The last 10% of features is 50% of the work. Don't declare victory when 90% of traffic is migrated — the remaining 10% often includes the most complex, least understood features.

5. Not decommissioning. After the migration, actually shut down the legacy system. Teams that leave it running "just in case" end up maintaining it indefinitely. Set a hard decommission date and stick to it.

The strangler fig pattern works because it reduces risk through incremental progress. You never have a big-bang moment where everything changes at once. Each step is small, verifiable, and reversible. The legacy system keeps running until the new system has proven it can handle everything. That's not just good engineering — it's good risk management.

Migration Legacy Systems Strangler Fig Architecture

become an engineering leader

Advanced System Design Cohort