Back to One: The Engineers Tearing Out Their Microservices and Sleeping Again
There's a certain kind of shame that comes with admitting you went too far. Developers don't talk about it at conferences. It doesn't make it into the case study blog post. But quietly, in Slack channels and engineering retrospectives from San Francisco to Austin, a growing number of teams are confessing the same thing: they over-distributed, and it cost them.
The monolith is back. Not the spaghetti nightmare your CTO warned you about in 2014 — the other kind. The deliberate, well-structured, single-deployable-unit kind. And for a lot of teams, it's the best architectural decision they've made in years.
How We Got Here
For most of the last decade, microservices weren't just a pattern — they were a personality. The tech industry sold them as the grown-up way to build software. Netflix did it. Amazon did it. The conference circuit ran on diagrams of service meshes and event buses. If you were serious about engineering, you broke things apart.
The problem? Most teams aren't Netflix. They're a 12-person startup trying to ship a product before their runway runs out, or a 40-person scale-up that suddenly realizes three engineers own a Kubernetes cluster nobody fully understands. The complexity that makes sense at massive scale becomes dead weight everywhere else.
"We had nine services for a product that had maybe 800 active users," says one senior engineer at a Series A fintech based in New York who asked to stay anonymous. "Deploying a feature meant coordinating across four repos, two teams, and a CI pipeline that took 40 minutes on a good day. We were doing distributed systems cosplay."
They spent three months consolidating back into a single Rails monolith with clear internal module boundaries. Deployment time dropped to under seven minutes. Onboarding a new engineer went from a week of environment setup to an afternoon.
The Complexity Tax Is Real
Here's the thing nobody puts in the architecture diagram: distributed systems are expensive to operate in ways that don't show up until you're deep in it. You're paying a complexity tax on every debug session, every incident, every new hire who has to learn which service owns which data.
Network calls fail. Services drift out of sync. Schema changes ripple in weird ways across team boundaries. Tracing a bug that crosses three service boundaries on a Friday afternoon is a special kind of misery.
A well-designed monolith sidesteps most of that. Function calls don't fail due to network timeouts. Transactions are just transactions — you don't need a distributed saga pattern to maintain consistency. And when something breaks, the stack trace actually tells you where.
Dan McKinley, a longtime engineering leader who's been vocal about the hidden costs of microservices, has framed it plainly before: innovation tokens are finite. Every exotic infrastructure choice you make is a token spent. Spend too many, and you've got no budget left for the actual product.
What a Modern Monolith Actually Looks Like
This isn't about writing a 300,000-line PHP file and calling it done. The teams doing this well are thoughtful about internal structure. They're using modular monolith patterns — clear boundaries between domains, enforced through folder structure, module systems, or even just strong team conventions.
In Ruby, that might look like Rails Engines. In Python, it's clean package separation with enforced internal APIs. Go developers are leaning into packages with strict dependency rules. The code is organized as if it might someday be split up — but it doesn't pay the tax of actually being split up until there's a real reason.
"We treat our modules like services in terms of how we think about ownership and interfaces," says an engineering manager at a SaaS company in Chicago that recently consolidated from a microservices architecture. "But they're not services. They're just code. And that distinction matters more than I expected."
The result is a codebase that can be reasoned about by a single engineer, deployed as a unit, and tested end-to-end without spinning up a dozen containers.
When Microservices Still Make Sense
Let's be fair: distributed systems solve real problems. If you have genuinely independent scaling requirements — say, a video transcoding pipeline that needs to burst independently from your API layer — a service boundary makes sense. If you have multiple teams that truly cannot coordinate deployments, separation buys you autonomy.
But those are specific, earned reasons. Not defaults.
The mistake most teams made was adopting microservices as an aspiration rather than a solution to a specific, felt problem. "We'll need to scale someday" is not the same as "we need to scale this specific thing right now in a way a monolith can't handle."
Scaling a monolith horizontally behind a load balancer gets you further than you'd think. Plenty of companies have run at significant scale on a single-process architecture. Stack Overflow famously served millions of requests from a relatively small number of servers running a monolithic .NET application. Basecamp has been explicit about running on a monolith for years and has no regrets.
The Shipping Dividend
The thing teams keep reporting after the consolidation isn't just fewer incidents — it's momentum. The psychological weight of a complex distributed system is hard to quantify until it's gone.
When a developer can clone one repo, run one command, and have the entire system running locally, they move differently. They're not afraid to touch code they don't own because they can see how it connects to everything else. Refactoring feels possible again. Experimentation gets cheaper.
"We shipped more features in the two months after consolidating than we had in the previous six," the New York fintech engineer said. "That's not a coincidence."
For early adopters and builders who care about velocity — and if you're reading RE09, you probably do — that's the real argument. Not purity, not ideology. Just: can your team ship the thing?
The Lesson
Architecture is a tool, not a trophy. The best system is the one your team can actually understand, operate, and improve. For a lot of teams right now, that's a monolith with clear internal structure and a boring deployment pipeline.
Going backwards, in this case, is how you move forward.