Why Some Engineering Teams Are Going Back to the Monolith


For most of the last decade, “microservices” was the default answer to “how should we structure our backend.” Splitting a system into small, independently deployable services became the industry-standard architecture, taught in bootcamps and assumed in job postings. Lately, though, a quieter counter-trend has been building: teams consolidating services back into fewer, larger deployables, sometimes all the way back to a single application. This isn’t a rejection of everything microservices offered. It’s a correction to how the pattern got applied.

The Promise That Sold the Pattern

Microservices emerged to solve problems that showed up at genuine scale: teams stepping on each other in a shared codebase, one team’s bug taking down an unrelated feature, deployments that required coordinating dozens of engineers, and the inability to scale one hot code path without scaling everything around it. Splitting services by domain let teams own their piece end to end, deploy on their own schedule, and scale independently. For companies operating at the size where these problems are real, the tradeoffs make sense.

The trouble is that the pattern got generalized far past that context. Plenty of teams adopted microservices not because they’d hit those scaling walls, but because it was the architecture everyone was writing about, interviewing for, and building tooling around. A ten-person startup with one product and one database ended up running twenty services because that’s what “good architecture” was assumed to look like.

Where the Costs Piled Up

A distributed system is a different kind of hard than a large codebase. Splitting an application into services introduces network calls where there used to be function calls, which means new failure modes: timeouts, retries, partial failures, and the need for distributed tracing just to answer “why is this request slow.” Local development gets harder because running “the app” now means running a dozen apps and their dependencies, or maintaining an increasingly elaborate mock environment. Data consistency, which was mostly free inside a single database transaction, becomes something you have to design around explicitly.

None of this is fatal. It’s the cost of the tradeoff. But it’s a cost that a lot of teams paid without getting the corresponding benefit, because they never had the deployment, scaling, or organizational problems microservices were built to solve. The overhead showed up immediately; the payoff never arrived.

The Modular Monolith Middle Ground

The response gaining traction isn’t a full return to the tangled monoliths of the 2000s, where everything was intertwined and nobody could safely touch shared code. It’s what’s often called a modular monolith: a single deployable unit, internally organized into well-defined modules with clear boundaries and interfaces, much like a set of microservices would be, but running in one process and talking through in-process calls instead of the network.

This gets you a good chunk of the organizational benefit, clear ownership, enforceable boundaries, code that’s easier to reason about, without paying the distributed systems tax on every request. If a module later genuinely needs to scale independently or be owned by a separate team with a separate deploy cadence, it’s a much smaller step to extract it into its own service, because the boundary already exists in the code. Extraction becomes a deliberate, targeted move rather than the starting assumption.

Picking the Right Default

The real lesson isn’t that microservices are wrong or monoliths are right. It’s that architecture decisions made by default, because of what’s trendy or what shows up in system design interviews, tend to age badly. The teams rethinking their service boundaries now are mostly asking a more basic question: does this split solve a problem we actually have, in terms of team size, deployment independence, or scaling needs? If the answer is no, a monolith with good internal structure is usually simpler to build, run, and reason about, and it doesn’t foreclose splitting things apart later once the need is real rather than assumed.