As an application grows, a familiar proposal eventually appears: split it into microservices. Sometimes that is the right move. In other cases it adds distribution, networking and operational complexity without solving a real problem.
1. Does this component need independent deployment?
The first criterion is not code size but the need for independent deployment. If two modules are always released together, depend on the same changes and require coordination between the same developers, putting them in separate services adds a network boundary without creating real autonomy.
An independent service should be changeable, testable and deployable without forcing the rest of the system to be released at the same time. That requires stable contracts, versioning and compatibility between versions.
2. Is there a truly independent data boundary?
Separating code is relatively easy. Separating data is much harder. A microservice that continuously queries another service's tables, shares the same SQL schema or participates in the same transactions is not truly independent.
Before extraction, clarify data ownership, which invariants must remain local and which information can be exchanged through APIs or events. Moving classes to another process does not fix an unclear data boundary.
3. Does it have different scaling requirements?
One advantage of microservices is the ability to scale only the component that needs it. But this is useful only when load characteristics are genuinely different. Splitting a module with the same traffic profile and resource needs as the rest of the application rarely creates proportional value.
Measure CPU, memory, response times, queues, throughput and database pressure before introducing a new service. Scaling decisions should respond to observed data, not assumptions.
4. Can a team really own it independently?
Organizational architecture matters. If every service change still requires work or approval across multiple teams, the technical boundary does not create independence. A service becomes much more meaningful when one team can own functionality, data, deployment and observability end to end.
5. Are we willing to pay the platform tax?
A separate process introduces costs that are absent or simpler in a monolith: service discovery, distributed configuration, secret management, timeouts, retries, circuit breakers, distributed tracing, log correlation, health checks, multiple deployments, API versioning and network-failure diagnosis.
This is the platform tax. It does not make microservices wrong; it means the value of independence must justify a permanent operational cost.
The distributed monolith risk
The worst outcome is often a system made of many services that must be deployed together, share the same database and call each other synchronously through deep chains. It is distributed in topology but still monolithic in behavior, now with extra timeouts and failure modes.
A useful test is: can I change and deploy this service without coordinating the release of the others? If the answer is almost always no, the independence is probably nominal.
The modular monolith as a starting point
For many .NET systems, a modular monolith provides a strong compromise. Modules have explicit boundaries, controlled dependencies and clear responsibilities while remaining in the same process and sharing a simpler deployment pipeline.
This does not block future evolution. A well-isolated module is often the best candidate for extraction when a concrete need for independent deployment, scaling or ownership emerges.
Extract gradually instead of rewriting everything
When a boundary is mature, extraction can be incremental: define the contract, reduce direct dependencies, separate data access, introduce an adapter and move traffic progressively. In legacy systems this is usually less risky than a full rewrite.
Conclusion
The useful question is not “monolith or microservices?” in the abstract. It is: what concrete problem will this distributed boundary solve?
If the answer is real independence in deployment, data, scaling or team ownership, extraction may be justified. If the goal is simply to make the system look more modern, a well-designed modular monolith may be a simpler, cheaper and more reliable foundation.
In summary
Split the system only when the boundary creates real independence.
Deployment, data, scaling and ownership should be able to evolve independently. Otherwise, a well-designed modular monolith can provide clear boundaries with far less operational complexity.
Related guides
Are you planning how to evolve an existing .NET application?
I can support software houses and development teams with architecture assessment, legacy modernization and pragmatic evolution paths — without introducing distributed complexity where it does not provide measurable value.