Microservices Aren’t the Default Anymore. And That’s a Good Thing
Microservices can solve real scaling and organizational problems, but they also introduce distributed-system complexity that many teams simply don’t need. Here’s why a modular monolith is often the better starting point and the signals that tell you when it’s time to split
There is a particular kind of engineering meeting that almost every growing startup eventually has.
The application is getting bigger. Deployments are becoming annoying. Several developers are touching the same parts of the codebase. Someone draws a box around “users,” another around “payments,” another around “notifications,” and eventually someone says:
“We should probably move to microservices.”
It sounds reasonable.
It also might be completely wrong.
The software industry spent years treating microservices as the natural destination for any application that had ambitions beyond a small startup. The architecture diagrams looked clean. Each service had its own responsibility. Teams could deploy independently. Scaling sounded easier.
Then people actually had to operate these systems.
The problem isn't that microservices are bad. They aren't. They solve some very real problems.
The problem is that teams often adopt them before they have the problems that justify them.
And that distinction matters more than almost anything else in architecture.
Microservices Don't Remove Complexity
A monolith has complexity.
Everyone knows this because developers have been complaining about monolithic applications for decades.
The codebase gets large. Boundaries become blurry. One change can have unexpected consequences somewhere else. Eventually, the application becomes difficult to understand and risky to modify.
But splitting that application into services doesn't make the complexity disappear.
It moves the complexity somewhere else.
A function call becomes an HTTP request. A local database transaction can become a distributed consistency problem. A simple stack trace can become a distributed trace. One deployment becomes several deployments. A failed database query becomes a question about whether the service, network, queue, timeout, retry policy, or downstream dependency is responsible.
You haven't deleted complexity.
You've changed its location.
That can be a very good trade.
But it is still a trade.
Recent discussions around architecture have increasingly focused on exactly this point: microservices can replace application complexity with operational and coordination complexity, while a well-designed monolith can remain surprisingly effective as a system grows.
The Architecture Advice We Keep Getting Wrong
A lot of architectural advice is accidentally written for companies that already have enormous engineering organizations.
Netflix has different problems from a four-person SaaS team.
Amazon has different problems from a startup validating its first product.
A company with hundreds of engineers working across dozens of domains may desperately need independent deployment boundaries. A team of five developers probably doesn't need twenty deployment pipelines.
This is where architecture discussions often become disconnected from reality.
Engineers look at the architecture of successful companies and copy the visible structure without copying the conditions that made that structure necessary.
That's backwards.
Architecture should respond to constraints.
It shouldn't create constraints simply because another company eventually needed them.
A Modular Monolith Is Not a Messy Monolith
There's an important distinction that gets lost in the monolith-versus-microservices argument.
A monolith doesn't have to mean one giant folder where every module imports everything else.
You can build a monolith with strict boundaries.
Imagine an application with modules for:
Users
Billing
Orders
Notifications
Reporting
Each module can have its own domain logic, services, repositories, interfaces, and tests.
The billing module doesn't reach directly into the internals of orders. The reporting module doesn't randomly modify user records. Dependencies are explicit. Shared infrastructure is kept small.
Everything still runs as one application.
That's a modular monolith.
And it gives you something extremely valuable: cheap communication.
When two modules need to interact, you're generally making an in-process call rather than crossing a network boundary. You don't need to serialize data into JSON, wait for a remote service, handle a timeout, retry a request, propagate authentication, or wonder whether the other service is currently available.
Research on modular monoliths has specifically identified this architecture as a practical alternative to microservices and, in some cases, a useful stepping stone toward later service extraction.
That last part is important.
You don't have to decide your entire distributed architecture on day one.
Designing good boundaries today can make extraction possible tomorrow.
When Microservices Actually Earn Their Keep
There are legitimate reasons to introduce services.
The strongest ones usually aren't “our codebase is getting big.”
Size alone isn't a good reason.
Instead, look for differences in scaling, ownership, reliability, deployment, or technology requirements.
Suppose your video-processing workload consumes enormous amounts of CPU while the rest of your application mostly handles ordinary web requests.
Running everything together means scaling the entire application just to handle one expensive workload.
That's a good candidate for separation.
Or imagine that your company has several engineering teams working independently on clearly defined business domains. If every team has to coordinate through a single deployment and shared application lifecycle, the monolith may become an organizational bottleneck.
That's another legitimate reason.
There are also cases where fault isolation matters.
If a recommendation engine occasionally becomes overloaded, you may not want that workload taking down checkout.
A separate service can give you a useful failure boundary.
This is what microservices are good at.
Independent scaling.
Independent deployment.
Team autonomy.
Fault isolation.
Different technology or runtime requirements.
But notice something about all of those reasons.
They're specific.
“Everyone says microservices are more scalable” isn't specific.
What needs to scale independently?
Why?
By how much?
What does separating it cost?
Those are architecture questions worth answering.
The Distributed Monolith Is the Worst of Both Worlds
There's another architecture that deserves more criticism: the distributed monolith.
This is what happens when a team splits an application into multiple services but keeps the old coupling.
Service A cannot work without Service B.
Service B cannot deploy without Service C.
Service C shares a database with Service A.
A request travels through six services before returning a response.
Every service has to be deployed together anyway.
Now you have the operational complexity of microservices without the independence that was supposed to justify it.
You traded a simple function call for a network request and got almost nothing in return.
This is why drawing more boxes on an architecture diagram doesn't automatically make a system better.
The boundary has to buy you something.
Otherwise, it's just another place for production to break.
The Database Is Usually Where Things Get Interesting
One of the hardest parts of splitting a monolith isn't writing the services.
It's figuring out who owns the data.
Inside a monolith, multiple modules can often participate in the same database transaction.
Move those modules into separate services and that convenience starts disappearing.
Now you have questions like:
Who owns the customer record?
Can billing update it?
Should orders keep a copy?
What happens if payment succeeds but order creation fails?
Should the system retry?
How do we make the operation idempotent?
How quickly does data need to become consistent?
These aren't implementation details.
They're architectural decisions.
A service boundary often forces you to confront data ownership and consistency problems that the monolith allowed you to ignore.
Sometimes that's exactly what you need.
Sometimes it's a needless complication.
The key is knowing which situation you're in.
Start With the Architecture You Can Operate
There's a simple test I like for architecture decisions:
Can the current team operate this system confidently at 2 a.m.?
Not theoretically.
Not after reading the documentation.
Actually operate it.
Can someone identify why requests are failing?
Can they deploy a fix without coordinating with five other teams?
Can they restore the database?
Can they understand the dependency chain?
Can they reproduce an incident locally?
Can they explain which service owns a piece of data?
If the answer is no, adding more services probably isn't going to make the situation better.
Operational maturity matters.
Microservices come with a substantial operational surface area: service discovery, observability, deployment orchestration, secrets, networking, retries, timeouts, queues, health checks, versioning, and failure handling.
None of these are impossible.
But every one of them needs to work.
The architecture has to fit the team's ability to run it.
When Should You Split?
Don't wait until the monolith is completely unmanageable.
But don't split simply because it feels modern either.
Look for concrete pressure.
A module needs radically different scaling characteristics.
A team needs to deploy independently.
A component requires a different reliability boundary.
A domain has become stable enough to define a meaningful API.
A workload needs its own infrastructure.
A particular part of the system is slowing down every other part.
Those are useful signals.
“It's getting big” isn't.
Neither is “we might need this someday.”
Future-proofing is one of the easiest ways to spend today's engineering budget solving tomorrow's imaginary problem.
Build for Change, Not for Certainty
The best architecture isn't the one that looks most sophisticated on a whiteboard.
It's the one that lets you change your mind cheaply.
That's the real advantage of a modular monolith.
You can establish boundaries without immediately paying the distributed-systems tax. If the business grows and one module eventually needs to become a service, the boundary already exists.
You extract it.
Maybe the first extraction is billing.
Maybe it's search.
Maybe it's media processing.
Maybe nothing ever needs to leave the monolith.
That's fine too.
Architecture isn't a loyalty program.
You don't get extra engineering points for running 47 services.
The goal is to build software that your team can understand, change, deploy, and operate without unnecessary pain.
Sometimes that means microservices.
Sometimes it means a monolith.
And increasingly, the sensible answer is somewhere in between.
The important question isn't “Which architecture is best?”
It's:
“What problem are we trying to solve by introducing this boundary?”
If you can't answer that clearly, don't create the boundary yet.
Keep the system simple. h Make the modules strong.
Ship the product.
Then let real constraints not architecture fashion—tell you what needs to split.
Keep reading
10 Tech Startups You Can Actually Start Without Millions: The 2026 Opportunity List
You do not need to build the next billion-dollar platform to start a serious technology company. Here are 10 practical startup opportunities across cybersecurity, healthtech, robotics, developer tools, fintech, climate, infrastructure and more, ranked by startup difficulty, cost, demand, scalability and how quickly a small technical team can get to its first paying customer.
Read articleThe Battery Revolution Is Already Here. It Just Isn't the One We Were Promised.
For years, the technology industry has promised us miraculous solid-state batteries that charge in minutes and transform everything from phones to electric cars. But while solid-state keeps slipping into the future, a quieter battery race is already changing the products around us.
Read articleThe Internet Isn't Really Distributed, We're Just Pretending It Is.
We built the internet around the idea of decentralization, then quietly moved enormous parts of it onto a handful of infrastructure providers. The result is an internet that feels distributed to users but can become surprisingly fragile when one cloud, DNS system, network provider or data center has a bad day.
Read article