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 it on Codelit
GitHub Integration
Paste any repo URL to generate an interactive architecture diagram from real code
Related articles
Try these templates
Build this architecture
Generate an interactive architecture for Microservices Decomposition Strategies in seconds.
Try it in Codelit →
Comments