Strangler Pattern: How I Modernize Monoliths Without a Big-Bang Rewrite

How I use Strangler-style migration to move legacy project/tender information systems toward services incrementally, with routing, data ownership, anti-corruption layers and rollback.

Romharshan Singh
Romharshan SinghSenior Solution Architect • AI & Cloud Mentor
1 September 20263 min read0 viewsUpdated 1 Sept 2026
Strangler Pattern: How I Modernize Monoliths Without a Big-Bang Rewrite

Strangler Pattern: How I Modernize Monoliths Without a Big-Bang Rewrite

Why I avoid the big-bang rewrite

In older project/tender information and distribution-style platforms, the legacy system often contains years of undocumented rules.

A statement like:

we will rebuild everything in microservices in six months

usually underestimates:

  • hidden validation;
  • scheduled jobs;
  • data cleanup rules;
  • partner integrations;
  • operational workarounds;
  • historical reports.

I prefer Strangler migration when the old platform must continue running.

Step 1: Introduce a routing boundary

plaintext
Client
  |
Gateway / reverse proxy
  |--------------------------\
  |                           |
new Search Service       Legacy Monolith
new User Service         remaining routes

Nginx example:

nginx
location /api/search/ {
    proxy_pass http://new-search-service;
}

location /api/users/ {
    proxy_pass http://new-user-service;
}

location / {
    proxy_pass http://legacy-monolith;
}

Step 2: Choose a capability

I prefer a capability with:

  • clear boundary;
  • useful business value;
  • limited cross-module write coupling;
  • measurable output parity.

I do not start with the most dangerous financial/core workflow just to prove we can.

Step 3: Anti-Corruption Layer

Legacy models often have field names and assumptions I do not want in the new domain.

typescript
function toModernTender(
  legacy: LegacyTenderRecord,
): Tender {
  return {
    id: String(legacy.TENDER_NO),
    title: legacy.SUBJECT?.trim(),
    closingAt: parseLegacyDate(
      legacy.CLOSE_DT,
    ),
    buyerId: String(legacy.ORG_ID),
  };
}

The adapter is the boundary.

The new service uses:

plaintext
Tender
Buyer
ClosingDate

not every legacy column convention.

Step 4: Data ownership

The most dangerous transition is dual write:

plaintext
legacy writes table
new service writes same table

I define one write owner per migration stage.

Temporary read-sharing can sometimes be accepted, but the end state should be explicit.

Options:

plaintext
legacy remains write owner
 -> new service receives events/CDC

new service becomes write owner
 -> legacy calls new API or consumes replicated view

Step 5: Shadow comparison

Before cutting over a query, I can run:

plaintext
real request -> legacy response
           \-> new service response (not shown to user)

Compare:

plaintext
result count
business fields
latency
error rate

This is extremely useful for search/report migration.

Step 6: Percentage or cohort cutover

plaintext
internal users -> new
5% traffic     -> new
25%            -> new
100%           -> new

I keep the old path available during controlled validation.

Step 7: Decommission

A Strangler migration fails if every old component remains forever.

I track:

plaintext
capability
new owner
traffic cutover
data migration
old code disabled
old table/API decommissioned

What I learned

The main risk is usually data, not HTTP routing.

If ownership remains unclear, the new service can look modern while the old database remains the real monolith.

Production checklist

  • Inventory business capabilities.
  • Introduce one stable routing boundary.
  • Pick a low-risk first slice.
  • Build an anti-corruption layer.
  • Define one write owner.
  • Compare old/new behavior.
  • Cut over gradually.
  • Preserve rollback.
  • Monitor error/latency parity.
  • Decommission migrated legacy code.

FAQ

Why not rewrite everything?

Because incremental migration reduces scope, keeps business running and exposes hidden rules earlier.

Can old and new systems share a DB?

Sometimes temporarily, but one write owner and an exit plan are essential.

What is the biggest Strangler risk?

Stopping halfway and operating a permanently coupled hybrid architecture.

- [Microservices Design Patterns I Have Used in Real Enterprise Projects](/articles/microservices-design-patterns-real-enterprise-projects) - [Adapter and Anti-Corruption Layer](/articles/adapter-anti-corruption-layer-external-supplier-integrations)
  • Canary Deployment

  • Database per Service

    Architect's final take

    The Strangler pattern gives me evidence after every migration step. That is more valuable than a beautiful target diagram with no safe route from the current system.

Was this article useful?

Your feedback helps prioritize deeper technical content.

Romharshan Singh
ABOUT THE AUTHOR

Romharshan Singh

Senior Solution Architect and Full Stack Technology Leader with 20+ years of enterprise engineering experience across AI, cloud, distributed systems, Java, Node.js, React, Angular, Kafka and Kubernetes.