Backend
Microservices vs monolith: the decision most teams get backwards
Microservices solve a team-coordination problem. If you do not have that problem yet, they mostly add distributed-systems failure modes to a codebase that had none.
The usual framing is that monoliths are what you build before you know better and microservices are what you graduate to. That gets the trade-off backwards.
What microservices actually solve
The problem is team coordination, not performance.
When forty engineers work in one codebase, they collide. Releases queue behind each other. One team's change breaks another's tests. Deciding to upgrade a dependency requires agreement across groups with different priorities.
Splitting into services with clear boundaries lets teams release independently. That is the benefit, and it is a real one — at that size.
Notice what is not on the list: raw performance. A well-built monolith is usually *faster* than the equivalent set of services, because a function call is cheaper than a network request.
What they cost
Every service boundary introduces things that did not exist before:
- Network failure between components. A function call cannot half-succeed. A network call can time out after the work completed.
- Distributed transactions. Updating two databases atomically stops being possible. You need sagas, compensating actions, or accepting temporary inconsistency.
- Debugging across processes. A single user action spans five services. Without distributed tracing, finding where it went wrong is guesswork.
- Operational multiplication. Five services means five deployment pipelines, five sets of alerts, five things to keep patched.
- Schema coordination. Changing a shared field now requires a coordinated release across teams — the exact problem you split to avoid.
For a team of six, you have paid all of that and received almost nothing.
The modular monolith
The middle path is usually correct: one deployable application, with strict internal module boundaries.
Modules communicate through defined interfaces rather than reaching into each other's internals. Each module owns its own tables and nothing else queries them directly. Dependencies between modules are explicit and enforced in CI.
You get most of the organisational benefit — clear ownership, contained blast radius, understandable structure — with none of the distributed-systems cost. And when a module genuinely needs to become a service later, the boundary already exists and the extraction is mechanical.
When splitting is genuinely right
Different scaling profiles. One component needs twenty instances at peak while everything else needs two. Splitting lets you scale only the expensive part.
Different runtime requirements. A machine learning component needs Python and a GPU; the rest is TypeScript on small instances. Forcing them together helps nobody.
Genuine team independence. Multiple teams, each owning a distinct business area, each wanting to release without coordinating.
Isolation requirements. A component handling payment data needs a stricter compliance boundary than the rest of the system.
Those are all real reasons. "We might need to scale someday" is not.
The comparison
| Monolith | Modular monolith | Microservices | |
|---|---|---|---|
| Team size that suits it | 1–10 | 5–30 | 25+ |
| Deployment | One pipeline | One pipeline | One per service |
| Transactions | Straightforward | Straightforward | Hard |
| Debugging | Single process | Single process | Needs tracing |
| Independent releases | No | Partially | Yes |
| Operational burden | Low | Low | High |
A practical recommendation
Start with a modular monolith and take module boundaries seriously from the first commit. Deploy it as one unit. Add observability early.
Split a module out when you have a specific reason you can state in one sentence — a scaling profile, a runtime requirement, a team boundary. If the reason is "this is what proper architecture looks like", the split is premature.
The teams we see in the most difficulty are not the ones running a large monolith. They are small teams operating twelve services, spending most of their time on infrastructure rather than the product.
Related: API development and DevOps.
MI Technologies Engineering
Software engineering team at Mohansh Innovations Pvt. Ltd.