Monolith vs. Microservices: What We Actually Choose and Why
Microservices get the conference talks. Monoliths get the actual work done. Here's our honest default, and the specific conditions that flip it.

Microservices get the conference talks, the architecture diagrams that look impressive in a pitch deck, and the reputation for being what "real" engineering organizations do. Monoliths get the actual work done for most of the projects we build. Here's our honest default, and the specific conditions that flip it.
We Default to Monolith
For the overwhelming majority of client projects — a new product, a business application, most SaaS tools in their early years — we start with a monolith. One codebase, one deployment, one database, clear internal module boundaries. This isn't a compromise or a starting point we plan to graduate from. For most projects at most stages, it's the correct architecture, full stop.
The reasons are practical, not ideological:
Deployment simplicity. One service to build, test, and deploy means fewer moving parts that can independently break. A monolith's failure modes are simpler to reason about because there's one process, one log stream, one place to look when something goes wrong.
Development speed. Making a change that touches multiple parts of the system is a single pull request in a monolith. In microservices, the same change might require coordinated deploys across three or four services, each with its own versioning and backward-compatibility concerns. For a small team moving fast, this overhead is real and constant.
Debugging is dramatically simpler. A request that fails in a monolith has one stack trace. A request that fails in a microservices architecture might have failed at any of several service boundaries, and tracing it requires distributed tracing infrastructure that itself takes real engineering investment to set up and maintain well.
Lower operational overhead. Microservices require service discovery, inter-service authentication, network reliability handling, and typically a container orchestration layer. All of that is infrastructure you have to build, monitor, and maintain — infrastructure that exists to solve a scaling problem you may not have yet.
When We Actually Reach for Microservices
We're not dogmatic about this either direction. A handful of real conditions justify the added complexity:
Genuinely independent scaling needs. If one part of your system needs to handle 100x the load of another part — a media processing pipeline versus a low-traffic admin panel, for example — splitting them lets you scale the expensive part without paying for that scale everywhere. This is the clearest, most legitimate reason to reach for microservices.
Multiple teams that need to deploy independently. At a certain organization size, having every team's changes go through one shared deployment pipeline becomes the actual bottleneck. Microservices let teams own their piece and deploy on their own schedule. This threshold is higher than most people assume — it's an organizational scale problem, not a code size problem.
A specific component with genuinely different technical requirements. If one piece of your system is better suited to a different language or runtime — a machine learning inference service, for instance — separating it out to use the right tool for that specific job can make sense, independent of the general architecture debate.
What We've Learned From Getting This Wrong
We've built microservices architectures for client projects where, in hindsight, a monolith would have served them better — usually because the team pushed for microservices based on what they'd read rather than an actual scaling or organizational need they were hitting. The result in those cases was months of infrastructure work (service mesh, distributed tracing, deployment orchestration) that delivered no business value the client could point to, while the actual product work slowed down under the weight of coordinating changes across services that didn't need to be separate.
The pattern we've also seen: a monolith that grew for years past the point where it should have split, because nobody made the deliberate scaling decision — they just kept adding to what existed because it was easier than solving the actual bottleneck. Both failure modes are real. The fix for both is the same: make the monolith-vs-microservices decision based on an actual, current requirement, not a prediction about scale you don't have yet and might never reach.
The Actual Rule We Use
Start with a monolith, structured with clear internal boundaries between modules so that if you do eventually need to split something out, the seams already exist. Split into a separate service only when you hit one of the three conditions above — not before, and not because it's what bigger companies do. Most projects never hit those conditions, and the ones that do will know it clearly when they get there, because the pain of not splitting becomes obvious rather than theoretical.