From monolith to modular

Picture of Mariam Laouiti
Mariam Laouiti

Author

Breaking a monolith apart is not free, and it is not always the right move. The honest answer to “should we go modular?” is that it depends on which problem is actually hurting you. If a single change forces a full redeploy, if two teams keep colliding in the same codebase, or if one feature has to scale while everything else sits idle, modular architecture earns its keep. If none of that is true, splitting a working monolith into a dozen services often buys you the operational cost of a distributed system with none of the benefit.

This is a decision that lands on the CTO and the IT director, and it is reversible only at high cost. So the question is not whether modular is fashionable. It is whether your specific pain maps to what decomposition solves, and whether you can run the distributed system you would be left with. Below is how to make that call, and how to execute it without a high-risk rewrite.

Key Takeaways

  • Modular architecture solves three specific problems: deployment coupling, team coordination friction, and uneven scaling. If you do not have these, a well-structured monolith is cheaper to run.
  • The strangler fig pattern, introduced by Martin Fowler and documented in AWS Prescriptive Guidance, extracts capabilities one at a time behind a proxy, avoiding the risk of a big-bang rewrite.
  • Premature decomposition is a real failure mode. Getting service boundaries wrong is far harder to fix than a refactor inside a monolith.
  • Distributed systems carry permanent costs: network latency, eventual consistency, distributed tracing, and on-call burden. Named teams at Amazon Prime Video and Twilio Segment moved back to a monolith and cut cost and overhead.
  • The modular monolith is a valid destination, not just a waypoint. Clear internal boundaries can deliver most of the benefit without the network tax.

The market is moving toward modular designs, which is partly why the question keeps coming up. The cloud microservices market was valued at USD 2.21 billion in 2025 and is projected to reach USD 9.64 billion by 2034, a 17.37% CAGR, per Fortune Business Insights. Growth is real. That does not mean every system belongs in that market. Application architecture modernization is a portfolio decision, made one application at a time, not a mandate applied to everything you run.

What modular architecture actually means

Monolith: an application where most functionality runs in a single process or deployable unit, with code that is tightly coupled and deployed together. A change to one area requires retesting and redeploying the whole thing.

Microservices: an architecture that splits an application into small, independently deployable services, each owning its own data and communicating over the network, usually through APIs or messaging.

The word “modular” sits between those two. A modular monolith keeps everything in one deployable unit but enforces strict internal boundaries: clear modules, defined interfaces, and no reaching across boundaries to share a database table directly. Microservices take those boundaries and put a network between them. Both are modular. Only one pays the distributed-systems tax. That distinction is the part most teams skip, and it is where most of the regret comes from.

The reason this matters: when people say they want to “move to microservices,” what they usually want is faster, safer change. You can get a large share of that from a disciplined modular monolith, without standing up service discovery, distributed tracing, and a platform team to run it all. Decide what you are actually buying before you commit to the more expensive version.

When to stay monolithic

Not every system needs to be broken apart, and a working monolith is not technical debt by default. If you have a small engineering team, business logic that is stable rather than sprawling, and a release cadence that the team can manage without stepping on each other, a well-structured monolith is the cheaper and faster choice. One codebase. One deployment. One place to look when something breaks.

Martin Fowler’s argument on this is worth taking seriously. In MonolithFirst, he writes that “you shouldn’t start a new project with microservices, even if you’re sure your application will be big enough to make it worthwhile.” The reason is the boundary problem. You rarely know where the real seams in your domain are until you have run the system in production for a while. Draw the boundaries too early and you cement the wrong ones, and “any refactoring of functionality between services is much harder than it is in a monolith.” Inside a monolith, moving a responsibility from one module to another is a refactor. Across services, it is a migration, with API contracts, data movement, and coordinated deploys.

The discipline that makes a monolith age well is the same discipline you would need for microservices anyway: clear modules with defined interfaces, no shared mutable state across boundaries, and a domain model that reflects how the business actually works. If you cannot keep a monolith clean, splitting it into services will not save you. It will distribute the mess across a network and make it harder to see.

Signs it is time to modularize

The signal to decompose is operational pain, not architectural fashion. Three patterns justify the move, and they are specific enough that you should be able to point to real incidents.

Deployment coupling

A change to one area forces a full system deploy and full regression. As AWS puts it, in a tightly coupled monolith “the changes cannot be tested in isolation, which impacts the cycle time.” If your release process has become a negotiation because every deploy carries the whole application, that is a coupling problem. Extracting the high-change parts into their own deployable units lets those teams ship without dragging the rest of the system along.

Team coordination friction

When several teams work in one codebase, ownership blurs and merges turn into bottlenecks. This is Conway’s law biting: your architecture and your org structure are fighting each other. Clear service boundaries that map to team boundaries reduce that friction. The key word is “map.” Splitting along technical layers when your teams are organized by business domain produces services that still cannot deploy independently, because every feature touches several of them.

Uneven scaling needs

In a monolith, you scale the whole application to handle peak load on one component. If one part of your system, payment processing during a sale, or report generation at month-end, has resource demands that are wildly different from everything else, isolating it lets you scale that part alone. This is one of the clearest wins for decomposition, because the cost saving is measurable: you stop paying to scale code that does not need it.

Underneath all three is the same test. Can you name the boundary, and is it stable? AWS warns that “the premature decomposition of systems can be costly, especially when the domain isn’t clear, and it’s possible to get the service boundaries wrong.” Domain-driven design and event storming exist to find those boundaries before you commit code to them. If you cannot describe a clean seam in plain language, you are not ready to cut along it.

The strangler fig pattern: how to migrate without a rewrite

Strangler fig pattern: a migration strategy, named by Martin Fowler, that replaces a monolith one capability at a time. New functionality is built as separate services, and a proxy routes traffic to either the old system or the new one, until the monolith can be retired.

The riskiest way to modernize is the big-bang rewrite: freeze the old system, rebuild everything in the new architecture, and switch over on a single day. AWS is direct about why this fails. “A big bang migration, where the monolith is migrated in a single operation, introduces transformation risk and business disruption. While the application is being refactored, it is extremely hard or even impossible to add new features.” For a bank or a healthcare provider, “we cannot ship anything for a year” is not an acceptable trade.

The strangler fig pattern, documented in detail by AWS Prescriptive Guidance, avoids that. You put a proxy layer in front of the monolith. At the start, it routes all traffic to the existing system. When you build a new capability, you build it as a service and tell the proxy to route that one path to the new code, leaving everything else untouched. You repeat this, capability by capability, until the monolith is a hollow shell you can decommission. Users experience continuity throughout, and you keep shipping features the whole time.

Two implementation details decide whether this works. First, the proxy or routing layer is a single point of failure if you build it naively, so it has to be highly available, not a fragile script in front of production. Second, when code still inside the monolith needs to call a capability you have already extracted, you put an anti-corruption layer between them. It is an adapter that converts the old internal call into the new service interface, so the rest of the monolith does not have to know that the capability moved. That loose coupling is what keeps regression risk low as you go.

Start at the edges. The first capability you extract should be relatively independent, with a clear boundary and few dependencies on the rest of the system. Route a small share of traffic to it, confirm it behaves, then increase. Each extraction teaches you something about your domain that makes the next one safer. This incremental learning is the real value of the pattern, not just the lower risk. AWS notes one caveat worth respecting: for a small application where a full rewrite is cheap, the strangler overhead may not be worth it. The pattern earns its complexity on large, business-critical monoliths, which is exactly where most of our clients live.

The cost of distributed systems, stated honestly

Once you put a network between your modules, you inherit a permanent set of problems that a monolith never had. Calls that used to be in-process function calls become network requests that can be slow, fail, or arrive out of order. A transaction that used to be a single database commit becomes a distributed operation spread across services, and strict consistency gives way to eventual consistency. Debugging a request now means tracing it across service boundaries, which is impossible without investment in logging, distributed tracing, and monitoring before you split. The old line holds: you cannot debug what you cannot see.

These costs are not theoretical, and they have driven named teams to reverse course. Amazon’s own Prime Video Video Quality Analysis team rebuilt a distributed serverless pipeline as a single process and reduced infrastructure cost by roughly 90%. The distributed design was hitting AWS Step Functions account limits because it performed multiple state transitions per second of video, and it was paying for constant data transfer through S3 between components. Their conclusion was not “microservices are bad.” It was that “microservices and serverless components are tools that do work at high scale, but whether to use them over monolith has to be made on a case-by-case basis.”

Twilio Segment told a similar story publicly. In Goodbye Microservices, the engineering team described consolidating more than 140 services back into one, after the overhead of running them all became a tax the team could not afford. Shared library changes meant redeploying dozens of services, on-call engineers were paged for load spikes on tiny destinations, and a small group spent most of its time keeping the system alive instead of building. Their summary: “Moving to a monolith allowed us to rid our pipeline of operational issues while significantly increasing developer productivity.”

The failure mode behind both stories has a name: the distributed monolith. You pay the full operational price of microservices, network latency, deployment orchestration, distributed debugging, but your services are still so tightly coupled that you have to deploy them together anyway. You get the costs of distribution and the constraints of a monolith at the same time. This is what premature or boundary-blind decomposition produces, and it is worse than the monolith you started with.

The modular monolith as a destination

Given those costs, the honest target for many teams is not microservices at all. It is a modular monolith: one deployable unit with internal boundaries enforced as strictly as if they were service boundaries. Modules talk to each other through defined interfaces, each owns its own data, and nothing reaches across a boundary to share state directly. You get clear ownership, testable modules, and a domain model that holds, without the network tax.

The strategic advantage is optionality. If you build clean module boundaries inside a monolith and one module later genuinely needs to scale independently or be owned by a separate team, extracting it into a service is straightforward, because the seam already exists. You have done the hard part, finding the boundary, without committing to distribution before you needed it. This is progressive modernization in practice: change the architecture in steps that each stand on their own, rather than betting the business on one large transformation.

The same logic governs the most regulated systems we work with. In core banking, a full core replacement is a multi-year, high-risk program. The lower-risk path is to run a modern core in a sidecar alongside the legacy ledger, ship new products against the new core, and migrate capabilities progressively rather than all at once. Kentro’s services across ERP, core banking modernization, and custom software are built on the same principle that governs the strangler fig: decompose where the pain and the boundary are real, leave the rest alone, and never put the business through a big-bang cutover it does not need.

How to decide, in order

Work the decision in sequence. First, name the pain. Is it deployment coupling, team friction, or uneven scaling? If you cannot point to a real, recurring problem in one of those three, stop. A working monolith is not a problem to be solved. Second, name the boundary. Use domain-driven design to identify where your domain actually divides. If the seam is not clear and stable, you are not ready to cut. Third, choose the lightest design that solves the named pain. Often that is a modular monolith, which removes the coupling without adding the network. Reserve full microservices for the boundaries where independent scaling or independent ownership is genuinely required.

Fourth, before you distribute anything, build the observability you will need to operate it: centralized logging, distributed tracing, and monitoring across boundaries. Splitting first and instrumenting later is how teams end up unable to debug their own system. Fifth, migrate with the strangler fig pattern, one capability at a time, behind a stable proxy, with anti-corruption layers where the old and new systems still talk. You keep shipping, you keep the risk bounded, and you learn the domain as you go.

Application architecture modernization done this way is unglamorous and reversible at each step, which is exactly what you want from a decision the business depends on. The goal was never “modular.” The goal was a system your teams can change safely and run affordably. Sometimes that is microservices. Often it is a clean modular monolith. The discipline is in matching the architecture to the real problem instead of the trend.

Frequently asked questions

How much does a monolith-to-modular migration cost?

There is no fixed figure, because the cost is driven by the size of the monolith, how tightly coupled it is, how clear your domain boundaries are, and whether you already have the observability and deployment infrastructure to run a distributed system. A modular-monolith refactor on a clean codebase is a different scope from extracting forty services from a tangled legacy core with data migration at every step. The engagement shape determines the price. The most useful next step is a short scoping conversation where we look at your actual system and pain points, so any estimate is grounded in your reality rather than a generic number. You can book a discovery call for that.

How long does it take?

The strangler fig approach is deliberately incremental, so you see value at each extraction rather than waiting for a final cutover. A first capability can often be extracted and serving traffic in weeks. Decomposing a large, business-critical system fully is typically a multi-quarter program run alongside normal feature delivery, not a single sprint. We scope it so the early steps deliver real relief, on deployment coupling or scaling, before the larger work is complete. Timelines are ranges until we have seen the codebase, the team structure, and the boundaries.

What is the ROI of going modular?

Return depends entirely on which pain you are removing. If deployment coupling is throttling your release rate, the return shows up as faster, safer shipping and less coordination overhead. If uneven scaling is inflating your cloud bill, the return is direct infrastructure cost, as the Prime Video case showed in the other direction. There is no fixed multiple, and any vendor quoting one is guessing. ROI is real only when it is tied to a named problem with a measurable baseline, which is what we establish before recommending any decomposition.

Should we use microservices or a modular monolith?

Default to the modular monolith and only distribute the boundaries that genuinely need it. A modular monolith gives you clear internal boundaries, independent module ownership, and a clean domain model without network latency, eventual consistency, or a platform team to run service infrastructure. Reach for microservices when a specific capability must scale independently, must be owned by a separate team, or has a release cadence that the rest of the system cannot match. Most systems need that for a handful of capabilities, not all of them.

What is a distributed monolith and how do we avoid it?

A distributed monolith is a set of services that still have to be deployed together because they are tightly coupled, so you carry the full operational cost of distribution with none of the independence that justifies it. It usually comes from splitting along technical layers instead of business domains, or from decomposing before the domain boundaries are clear. You avoid it by finding stable boundaries first, through domain-driven design and event storming, ensuring each service owns its own data, and confirming that services can be deployed independently before you call the work done.

Do we have to abandon our existing monolith to modernize?

No. The strangler fig pattern exists precisely so you do not have to. You keep the monolith running and serving users while you extract capabilities around it one at a time, behind a proxy, with anti-corruption layers where the old and new systems interact. The monolith is only decommissioned once its functions have been moved and validated. You are never forced into a freeze-and-rewrite, which is the highest-risk path and the one we steer clients away from. For examples of how we approach modernization across regulated industries, see our case studies.

Not sure whether to split your monolith or clean it up?

We will look at your actual system, name the real pain, and tell you the lightest architecture that solves it. No big-bang rewrites. Reach us at hello@thekentro.com.

Book a discovery call
The monolith-to-modular transition isn’t a binary choice or a one-time event. It’s a strategic journey that should be driven by your organization’s specific needs and constraints. Focus on solving real problems rather than achieving architectural purity. Start small, learn from each extraction, and build the organizational capabilities and infrastructure needed to support a distributed system. When done thoughtfully, modularization can unlock team velocity and system scalability. When done prematurely or carelessly, it can create unnecessary complexity that slows everything down.

© 2025 Kentro. Build. Secure. Scale.