The most interesting engineering story of the last three years is not a new tool or a new language. It is teams quietly, methodically, walking back one of the most expensive architectural decisions of the previous decade. Services that were carefully extracted from monoliths are being merged back in. The word “monolith” has been rehabilitated, or at least rebranded. The term “modular monolith” now gives the move a dignity that a straight retreat would lack.
This is not a war between camps. It is an honest reckoning with operational complexity, and the evidence comes from some of the most respected engineering teams in the industry.
The wave and the warnings that went unheeded
Between roughly 2015 and 2020, microservices became the default architectural answer for any company that could afford the hype. The definition, as Martin Fowler and James Lewis wrote in their foundational 2014 article, described an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms. The promise was clear: independent deployability, independent scalability, and teams that could move fast without stepping on each other.
What got less attention was the cautionary advice that accompanied the definition from the start. Fowler himself published a Bliki entry on MonolithFirst, advising that most teams should start with a monolith and only migrate to microservices when they had clear evidence the monolith was causing problems. David Heinemeier Hansson had made the same case even earlier, in his 2016 essay “The Majestic Monolith”, arguing that monoliths were a valid and powerful architecture for web applications.
The industry chose to ignore both. The wave crested on the assumption that microservices were the mature, scalable choice and that monoliths were legacy baggage. The warnings were treated as quaint reservations from people who simply had not seen the future. As it turned out, the future arrived with a bill.
The retreat in plain sight
Three engineering teams published accounts that, taken together, form a pattern too clear to dismiss.
Amazon Prime Video’s engineering team described in a March 2023 blog post how they consolidated their serverless monitoring services into a monolith. The motivation was not ideological. It was a 90 percent reduction in cost. The distributed architecture had created overhead that, when examined honestly, was simply not earning its keep. The team merged services, cut infrastructure, and the system ran better.
Shopify published a blog post in 2020 titled “Shopify’s Journey to a Modular Monolith” describing their own evolution. They had started with a monolithic Rails application, extracted services as the company grew, and then found themselves consolidating back into a modular monolith. The language matters. Shopify did not call it a retreat. They called it a modular monolith, a term that acknowledges the lessons of microservices while rejecting the distributed overhead.
GitHub’s engineering blog, in a 2021 post on how the company ships software, described their own architecture and deployment practices. While GitHub did not frame their post as a reversal, the picture that emerged was of a team that had learned the hard way about the coordination costs of distributed systems and had adjusted accordingly.
Three companies. Three different scales. Three different primary motivations: cost, maintainability, deployment speed. The common thread is that each found the operational burden of distributed services higher than the benefit for their specific context.
The modular monolith is not a regression. It is a synthesis that borrows the best ideas from microservices while rejecting the distributed overhead.
What the modular monolith actually means
The term “modular monolith” is not a euphemism for a messy codebase. It describes a deliberate architecture that enforces bounded contexts within a single deployable unit. The key insight is that you can have the domain boundaries that microservices promise without paying for the distributed systems tax.
Dino Esposito, in his 2024 book “Clean Architecture with .NET” published by Microsoft Press, devotes a chapter to the trade-offs between microservices and modular monoliths. His argument is that modular monoliths are often a better choice for many projects because they preserve the separation of concerns that makes microservices attractive while avoiding the network latency, serialization overhead, and operational complexity that come with distributed services.
Shopify’s post makes the same point from experience. Their modular monolith uses clear module boundaries within a single application. Teams still own distinct domains. Code still has explicit interfaces between modules. The difference is that those interfaces are method calls, not network requests. The team gets the organizational benefits of bounded contexts without needing to manage service discovery, circuit breakers, distributed tracing, and the rest of the microservices toolkit.
This is not a regression to the Rails-era monolith where everything was coupled and nothing was separated. It is a third option that synthesizes the best ideas from both approaches.
When microservices still earn their keep
The retreat does not mean microservices are wrong. It means the bar for choosing them has risen.
Fowler and Lewis’s original definition still holds for the cases where microservices genuinely fit. Large teams with clear domain boundaries. Systems where different services genuinely need to scale independently. Organizations where the cost of coordinating deployments across teams has become the primary bottleneck.
Fowler’s MonolithFirst advice is the framework that should have been applied all along. Start with a monolith. Extract services only when you have evidence that the monolith is causing a specific, measurable problem. Do not extract services because it feels like the grown-up thing to do.
Esposito’s analysis reinforces this. Microservices are a niche tool. They solve real problems for specific organizational and technical conditions. They are not a default architecture. The industry spent five years treating them as one, and the bill is now coming due.
The honest accounting of operational complexity
The true cost of microservices was never just the infrastructure bill. It was the cognitive and organizational overhead of distributed systems. Every service boundary introduces latency, failure modes, data consistency challenges, and debugging complexity that a monolith simply does not have.
Amazon Prime Video’s 90 percent cost reduction is striking, but the number that matters more is the one they did not publish: the engineering time spent managing the distributed system before the consolidation. The blog post focuses on infrastructure cost because that is measurable. The operational overhead of keeping distributed services running, debugging cross-service failures, and managing deployment coordination is harder to quantify but often larger.
Shopify’s modular monolith journey makes the same point from the other direction. The team found that the coordination cost of their service boundaries exceeded the benefit. The modular monolith gave them back the simplicity of a single deployable unit while keeping the domain separation that made microservices attractive in the first place.
The honest accounting is this: every service boundary is a bet that the benefits of separation will exceed the costs of distribution. For many teams, that bet did not pay off. The modular monolith is not a consolation prize. It is the architecture that was always the right answer for a large set of problems, and the industry is only now admitting it.