Back to Blog
microservicesmigrationarchitecturebackend

Practical patterns for migrating a monolith — without burning it down

January 28, 202612 min read

A field guide to incremental service extraction: strangler fig, anti-corruption layers, feature flags, and the mistakes I made along the way.

The big-bang rewrite fantasy

Every engineer who has worked on a legacy monolith has had the same thought: "Let's just rewrite it from scratch." And almost every team that acts on that impulse regrets it. The new system takes twice as long as expected. The monolith keeps accumulating bug fixes and features during the rewrite. By the time the new system is ready, it's already behind — and it inherited all the subtle business logic bugs that nobody documented.

The Strangler Fig pattern

The strangler fig is a tree that grows around its host, slowly replacing it from the outside in. Applied to software: instead of replacing the monolith, you route specific traffic slices away from it and into new services, one at a time. The monolith keeps running. Users don't notice. You strangle it gradually. In practice this means putting a proxy (Nginx, an API gateway, or a simple routing layer) in front of the monolith and redirecting specific URL prefixes or feature flags to new services as they're ready.

Anti-Corruption Layers

When you extract a service, it needs to talk to the monolith during the transition. Don't let the new service import the monolith's domain model — that creates exactly the coupling you're trying to escape. Instead, build an Anti-Corruption Layer (ACL): a translation module that converts between the monolith's concepts and the new service's domain. The ACL lives in the new service and is temporary. Once the monolith feature is fully retired, the ACL is deleted.

Feature flags for safe extraction

Feature flags let you deploy extracted services to production without exposing them to users. You can exercise the new path in staging, run it in shadow mode (fire requests at both old and new, compare responses), and gradually roll out by user segment. If something breaks, you flip the flag without a deploy.

The database problem

The hardest part of a monolith migration is the shared database. Microservices are supposed to own their data, but the monolith probably has one big relational database that everything touches. The migration path: first, identify which tables belong to the domain you're extracting. Then add an API layer over those tables in the monolith. Then cut the new service over to its own database and let the API layer handle the sync period.

Mistakes I made

1. Extracted too many services at once — each one was fine in isolation but the operational overhead multiplied. 2. Forgot to migrate the shared event bus, so events were still tying services together through the monolith's message queue. 3. Underestimated the "unknown" business logic buried in stored procedures. Rule of thumb: extract one service, run it in production for a month, learn from it, then extract the next.

Written by Luna Lancuba

← More articles