You Don't Have to Migrate Everything at Once

by Arif Ikhsanudin, Backend Developer

The sunk cost trap in migration projects

Twelve months into your microservices migration, you've extracted four of twenty planned services. Three of them are running well. One is a mess you're maintaining alongside the equivalent monolith code because the cutover never happened. Eight more services are "in progress" — meaning someone started an extraction six months ago, the branch diverged, and now merging back is a project unto itself. The remaining eight haven't been started.

Your engineers are spending 40% of their time on migration work. The monolith is still taking 60% of new features. You committed to "finish the migration" as an org-level goal, which means stopping is politically difficult even though stopping might be the right engineering answer.

This is the destination when "migrate everything" is the plan rather than "migrate what makes sense and evaluate." The premise that you need to extract every module into a service to benefit from microservices is wrong. The benefit comes from extracting the modules where microservices architecture provides specific, measurable value. For the rest, the monolith may be perfectly adequate.

Extracting by value, not by plan

Start each potential extraction with: what specific problem does extracting this module solve? If the answer is "our migration plan says to," that's not a good enough reason. If the answer is "the Search team wants to experiment with Elasticsearch and the current monolith's database-backed search is a bottleneck for their iteration velocity," that's a real reason.

Value-based extraction questions:

  • Does this module have scaling requirements significantly different from the rest of the monolith?
  • Does a specific team need deployment independence from this module to move faster?
  • Does this module have a compliance or security requirement that demands data isolation?
  • Is this module in a different language or runtime than the monolith, making it awkward to maintain in-process?

If none of those apply, the module might be better left in the monolith, possibly with improved internal boundaries. A well-bounded module inside a monolith is often easier to maintain than a separate service with all its operational overhead.

The hybrid architecture as a valid steady state

It is entirely acceptable — and often optimal — to run a hybrid architecture indefinitely: a monolith handling the majority of business logic, alongside a small number of services for components that genuinely benefit from independence.

A monolith plus a search service. A monolith plus an ML inference service. A monolith plus a real-time notification service. Each extracted for a specific, justified reason. The monolith is not a legacy thing to be eliminated — it's the appropriate deployment unit for the parts of the system where the monolith's simplicity outweighs the services' benefits.

The hybrid architecture requires one discipline: the monolith must not directly call into service code (it communicates via APIs or events), and services must not directly access the monolith's database. These boundaries make the hybrid sustainable. Without them, you get a distributed monolith — the worst of both worlds.

Managing the extraction backlog

If you're mid-migration with many planned extractions not yet started, evaluate each one against current criteria rather than original plan criteria:

For each un-started extraction:

  1. What was the original reason to extract this module?
  2. Has that reason materialized? Is it still the right problem to solve?
  3. What is the current cost of leaving it in the monolith?
  4. What would the extraction cost in engineering time, and what's the ROI?

Some modules that seemed like extraction candidates twelve months ago may no longer be worth extracting. New feature development has changed the system. Team structure has changed. Original pain points have been resolved other ways. Abandoning planned extractions that no longer make sense is not failure — it's updated decision-making with current information.

Stopping criteria

How do you know when you've done enough? When:

  • The teams that were blocked by the monolith are unblocked (they have deployment independence for their domains)
  • The scaling bottlenecks that required separation are resolved
  • The compliance requirements that demanded isolation are satisfied

Not when every module is a service. That endpoint is arbitrary and likely to produce overengineered infrastructure for modest benefit. The architecture is not a destination — it's a response to specific engineering and organizational requirements. When those requirements are met, stop extracting.

What you should preserve as you extract: the ability to move quickly within the monolith for new features that don't need to be services. A large, untangled, well-tested monolith core alongside a few well-chosen services is a legitimate long-term architecture for many organizations. Resist the pressure to complete a migration for its own sake.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

The Hidden Cost of Cheap Developers

“We found someone way cheaper — let’s go with them.” That decision often feels smart… right up until it isn’t.

Read more

Hourly vs Project Based Pricing: What Works Better for Backend Contractors

Neither pricing model is universally better — but choosing the wrong one for the wrong engagement costs you money, time, or both.

Read more

Why Your API Returns 200 Even When Something Goes Wrong

Returning HTTP 200 for failed operations hides errors, breaks client logic, and makes systems harder to debug. Using proper status codes is not pedantry—it’s critical for correctness and reliability.

Read more

Mandatory Office Days: A Contractor’s Productivity Nightmare

“We just need you in the office a few days a week.” Sounds harmless—until those days quietly become the least productive ones.

Read more