Skip to content
Architecture

Monolith to Microservices: A Step-by-Step Migration Guide

Aman Kumar· Founder & Engineering LeadPublished Updated 7 min read
Server racks in a data centre, representing distributed service infrastructure

Monoliths are not a mistake. Most should stay monoliths. But when a ten-year-old application needs a full-system deploy to change a button colour, you have a velocity problem — and that is a reason to decompose, where "it feels dated" is not.

Should you migrate at all?

Start here, because the honest answer is often no. Microservices trade a simple deployment story for a distributed systems problem: network failures, partial outages, no cross-service transactions, and far harder debugging. You are buying independent deployability and paying in operational complexity.

Decompose when at least two of these are true:

  • More than roughly 20 engineers are contending for the same deploy pipeline.
  • Release cadence is slower than weekly because of coordination, not testing.
  • One component's load forces you to scale the entire application.
  • Distinct parts genuinely need different runtimes or data stores.

If none of those apply, a well-modularised monolith will serve you better and cost less to run.

The strangler fig sequence

Named for the vine that grows around a tree until it stands on its own, this is the migration order we use. Do it once per domain, and finish each pass before starting the next:

  1. Put a gateway in front. All traffic routes through an API gateway while the monolith still serves every request. Nothing has changed functionally — you have simply gained a seam to redirect at.
  2. Pick a low-risk, low-coupling domain. Notifications, PDF generation, search indexing. Not billing, and not authentication.
  3. Build the service, and its data boundary. The service owns its own storage. If it still reads the monolith's tables directly, you have built a distributed monolith — the worst of both designs.
  4. Shadow the traffic. Send real requests to both paths, compare the outputs, and fix the differences before anything depends on the new service. This is the step most teams skip and most regret skipping.
  5. Cut over behind a flag, so reverting is a config change rather than a deploy.
  6. Delete the old code path. Not later — now. Dead code left in the monolith is the reason migrations stall half-finished and leave you maintaining both designs forever.
  7. Repeat with the next domain.

Planning a migration?

Our cloud architects can review your decomposition roadmap before you commit to it. Learn about our cloud services.

Service extraction35%Data separation25% — the usual blockerObservability setup15%Shadow testing15%Deleting old paths10%
Where migration effort actually goes on a typical six-domain extraction (Napnix delivery data, 2026). Percentages of total migration effort.

What breaks, and what to do about it

The four failure modes that account for most stalled migrations, and the standard remedy for each.
What breaksWhyRemedy
DebuggingOne request now spans several services and logsDistributed tracing via OpenTelemetry, from day one
TransactionsACID guarantees do not cross service boundariesSaga pattern with explicit compensating actions
Data ownershipShared tables recreate the coupling you removedOne datastore per service; integrate through APIs or events
Local developmentRunning twelve services on a laptop stops being practicalContainerised stack plus contract tests, not full local parity

What does a migration cost, and how long does it take?

The cost of a migration is rarely in writing the new services. It is in running two architectures at once, and that overlap is the line most plans omit. While the strangler fig is in progress you pay for duplicated infrastructure, data kept consistent across both sides, and engineers holding two mental models of the same system. Budget for that period explicitly rather than treating it as a transition cost that will somehow not arrive.

There is also a permanent operational cost on the far side, and it is the one that catches teams out. Microservices need things a monolith did not: distributed tracing, centralised logging, service discovery, per-service CI pipelines and someone on call who understands the topology. If you do not already have that platform capability, you are funding two projects — the migration and the platform underneath it.

A rough shape for a mid-sized application:

  • Months 1–2: instrumentation and seams. Add tracing and logging to the monolith first, because you cannot safely extract what you cannot observe.
  • Months 3–6: extract two or three services at the edges — notifications, reporting, file processing. Low coupling, real learning, and reversible if the approach is wrong.
  • Months 6–12: the hard middle. Services that share the database with the monolith. This is where most migrations stall, and where the data model decisions get made.
  • Ongoing: stop when the pain that justified the migration is gone. A permanently partial migration is a legitimate end state, and a far better outcome than a complete one nobody needed.

That last point is the one worth taking away. The goal was never to eliminate the monolith; it was to stop it blocking delivery. If extracting three services achieves that, extracting twelve is cost without benefit.

It is worth being blunt about the failure mode, because it is common and expensive: a team adopts microservices to fix a delivery problem that was actually a testing problem or an ownership problem, and arrives at a distributed system with the original bottleneck intact plus a great deal more operational surface. If releases are slow because the test suite takes two hours, faster tests are a far cheaper fix than a new architecture. Diagnose the constraint before you change the topology.

For the infrastructure side of this — assessing the cost baseline first, and deciding rehost versus refactor per workload rather than for the whole estate — see our cloud solutions page, or talk to us about where your delivery is actually blocked. We would rather tell you the constraint is your test suite than sell you an architecture programme you do not need.

The bottom line

Microservices buy deployment independence, and they are an investment in team speed rather than in raw performance. Migrate one domain at a time, keep each step reversible, and delete the old path every time. If your team is under twenty engineers and shipping weekly, the better architectural decision is usually to modularise what you have.

Sources

  1. StranglerFigApplication — Martin Fowler
  2. Saga pattern for distributed transactions — Microsoft Azure Architecture Center
  3. OpenTelemetry — vendor-neutral distributed tracing — Cloud Native Computing Foundation
  4. MonolithFirst — why starting with microservices usually backfires — Martin Fowler

About the author

Aman Kumar — Founder & Engineering Lead

Aman co-founded Napnix and leads its engineering work, building Napnix CRM and the custom CRM and automation systems Napnix delivers for agencies and service businesses.

Writes about custom crm development, enterprise software architecture, microservices migration.

First published Mar 25, 2024 · last reviewed Oct 5, 2026