Microservices Decomposition Strategies: How to Break a Monolith Apart
Every monolith eventually reaches a point where deploys take hours, teams step on each other's code, and a single bug in billing brings down search. Decomposition is the disciplined process of carving that monolith into independently deployable services. The hard part is not the cutting — it is deciding where to cut. This guide covers the major decomposition strategies, their trade-offs, and how to know when you have gone far enough.
Why Decompose?#
Microservices are not a goal — they are a tool for solving organizational and operational problems:
- Independent deployment — ship billing fixes without redeploying search.
- Team autonomy — each team owns a service end-to-end.
- Technology heterogeneity — use the best language or database for each problem.
- Targeted scaling — scale the recommendation engine without scaling the admin panel.
If none of these problems apply, a well-structured monolith is often the better choice.
Strategy 1 — Decompose by Business Capability#
A business capability is something the organization does to generate value: Order Management, Inventory, Payments, Shipping. Each capability maps to one or more services.
┌────────────────────────────────────────────┐
│ E-Commerce Platform │
├──────────┬──────────┬──────────┬───────────┤
│ Orders │ Inventory│ Payments │ Shipping │
│ Service │ Service │ Service │ Service │
└──────────┴──────────┴──────────┴───────────┘
How to Identify Capabilities#
- Map the value chain — from customer acquisition to post-sale support.
- Look for nouns in business language: "order", "invoice", "shipment".
- Each capability should have a clear owner and well-defined inputs/outputs.
Strengths#
- Aligns services with how the business thinks, making communication natural.
- Capabilities are relatively stable — the business will always need "Payments" even if the implementation changes.
Weaknesses#
- Cross-capability workflows (e.g., "place an order" touches Orders, Inventory, and Payments) need choreography or orchestration.
- Capabilities can be too coarse, hiding internal complexity.
Strategy 2 — Decompose by Subdomain (DDD)#
Domain-Driven Design gives you a more precise scalpel. The process starts with Event Storming or Context Mapping to discover bounded contexts.
Key DDD Concepts#
- Domain — the problem space your software addresses.
- Subdomain — a distinct area within the domain (core, supporting, or generic).
- Bounded Context — a linguistic and model boundary where a term like "Customer" has one unambiguous meaning.
- Ubiquitous Language — the shared vocabulary within a bounded context.
Mapping Subdomains to Services#
| Subdomain Type | Example | Service Strategy |
|---|---|---|
| Core | Pricing engine, recommendation AI | Build in-house, invest heavily |
| Supporting | Notification service, reporting | Build simply or buy |
| Generic | Authentication, email delivery | Buy or use SaaS |
Strengths#
- Produces services with high cohesion and low coupling.
- The ubiquitous language prevents misunderstandings across teams.
- Core subdomains get the investment they deserve.
Weaknesses#
- Requires significant upfront domain modeling effort.
- Bounded context boundaries can be hard to discover in legacy systems.
Strategy 3 — Decompose by Team#
Conway's Law states that system architecture mirrors organizational communication structures. Instead of fighting this, lean into it: give each team a service (or a few) that they fully own.
Team Topologies Alignment#
- Stream-aligned teams own services that deliver value to a specific customer segment or business flow.
- Platform teams own shared infrastructure services (API gateway, service mesh, CI/CD).
- Enabling teams help stream-aligned teams adopt new practices without owning long-lived services.
Guidelines#
- A service should be owned by exactly one team.
- A team should own no more services than it can operate in production.
- If two teams constantly need to coordinate changes, merge the services or merge the teams.
Strengths#
- Minimizes cross-team coordination overhead.
- Clear ownership means clear accountability for uptime and quality.
Weaknesses#
- Teams may draw boundaries around organizational politics rather than technical fitness.
- Reorgs can force awkward service reshuffling.
Strategy 4 — Decompose by Data#
Data ownership is often the strongest signal for service boundaries. If two features share a database table, splitting them into separate services introduces distributed data headaches. If they use entirely different tables, they are natural candidates for separation.
The Litmus Test#
Ask: "Can this service own its data store exclusively, with no shared writes?"
- Yes — clean service boundary.
- No, but reads are acceptable via events — use Change Data Capture (CDC) or domain events to replicate read models.
- No, shared writes are required — these features probably belong in the same service.
Data Decomposition Patterns#
Before:
┌────────────────────────────┐
│ Shared Database │
│ orders │ products │ users │
└────────────────────────────┘
After:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Orders DB│ │Products DB│ │ Users DB │
│ (Postgres)│ │ (Postgres)│ │ (Postgres)│
└──────────┘ └──────────┘ └──────────┘
▲ ▲ ▲
Orders Products Users
Service Service Service
Handling Cross-Service Queries#
- API Composition — the caller queries multiple services and joins client-side.
- CQRS read models — project events from multiple services into a denormalized read store.
- Materialized views via CDC — stream database changes into a shared analytics store.
Strategy 5 — Strangler Fig for Decomposition#
The Strangler Fig pattern lets you decompose incrementally. Instead of rewriting the monolith, you intercept requests at the edge and route them to new services one feature at a time.
Step-by-Step#
- Identify a seam — a feature with clear inputs and outputs.
- Build the new service alongside the monolith.
- Route traffic — use an API gateway or reverse proxy to send requests for that feature to the new service.
- Verify parity — run both paths in parallel, comparing outputs.
- Remove the old code from the monolith once the new service is proven.
- Repeat for the next feature.
┌─────────────┐
│ API Gateway │
└──────┬───────┘
│
┌──────┴───────┐
│ Router │
├──────┬───────┤
▼ ▼ ▼
New New Monolith
Svc A Svc B (remaining)
Anti-Corruption Layer#
When the new service needs data from the monolith, do not call monolith internals directly. Instead, place an Anti-Corruption Layer (ACL) that translates between the old model and the new bounded context. This prevents legacy concepts from leaking into your clean design.
Strengths#
- Zero big-bang risk — each migration is small and reversible.
- The monolith keeps running while you chip away at it.
Weaknesses#
- Maintaining two implementations in parallel increases short-term complexity.
- The gateway routing layer can become a bottleneck if not managed.
When to Stop Decomposing#
Not every module deserves its own service. Decomposition has diminishing returns and increasing costs.
Signs You Have Gone Too Far#
- Distributed transactions everywhere — if every user action spans three or more services with sagas, you split too aggressively.
- Chatty inter-service calls — services that cannot complete a request without calling two other services are coupled, not independent.
- Tiny teams, many services — if one developer owns five services, operational burden outweighs autonomy.
- Shared data under the hood — if two services share a database table through a back door, they are one service pretending to be two.
The Right Granularity#
A well-sized microservice:
- Can be understood by one team.
- Owns its data exclusively.
- Can be deployed independently without coordinating with other teams.
- Has a well-defined API contract that changes infrequently.
Nano-Services — The Anti-Pattern#
Splitting a service that handles a single CRUD entity with no business logic is a nano-service. It adds network latency, operational overhead, and deployment complexity with zero architectural benefit. Merge it back.
Combining Strategies#
In practice you will use multiple strategies together:
- Start with business capabilities to draw coarse boundaries.
- Apply DDD within each capability to find bounded contexts.
- Use data ownership as a validation check — if data cannot be cleanly separated, the boundary is wrong.
- Organize teams around the resulting services (inverse Conway maneuver).
- Execute the migration using Strangler Fig to avoid big-bang rewrites.
Decision Framework#
| Factor | Prefer Fewer, Larger Services | Prefer More, Smaller Services |
|---|---|---|
| Team size | Small org, few teams | Large org, many autonomous teams |
| Domain complexity | Simple, well-understood domain | Complex domain with many bounded contexts |
| Deployment frequency | Infrequent, coordinated releases | Continuous, independent deploys |
| Data coupling | Highly shared data | Cleanly separable data stores |
| Latency sensitivity | Sub-millisecond requirements | Tolerant of network hops |
Codelit publishes in-depth engineering articles every week. This is article #411 in the series — explore more on codelit.io.
Try these templates
Continue learning
Go deeper on microservices and integration
As an Amazon Associate I earn from qualifying purchases. Codelit may receive a commission at no extra cost to you.
Building Microservices
Sam Newman · 2021
600 pages on splitting a monolith: service boundaries, data decomposition, migration order.
Istio in Action
Christian E. Posta, Rinor Maloku · 2022
Hands-on Istio: mTLS, traffic shifting, retries, and debugging the sidecar when the mesh misbehaves.
4.6 (33)Kindle editionEnterprise Integration Patterns
Gregor Hohpe, Bobby Woolf · 2003
A catalog of 65 messaging patterns with diagrams - the vocabulary queue designs still use today.
4.6 (581)Learning Domain-Driven Design
Vlad Khononov · 2021
Turns bounded contexts and aggregates into decision rules for where service boundaries actually go.
4.6 (400)