The Architecture Decision With Long Consequences
The choice between monolithic architecture (all application components in a single deployable unit) and microservices architecture (application composed of independent, separately deployable services communicating over a network) is among the most consequential technical decisions in software development — it shapes the team structure, deployment processes, operational complexity, and scaling characteristics of everything built on top of it.
The decision has also become among the most politicised in software engineering, with strong advocates for both approaches making claims that don’t always survive contact with specific project realities. The honest assessment: monolithic architecture is the right starting point for most projects, and microservices make sense for specific situations that most projects don’t reach until they’ve already been successful for some time.
Monolithic Architecture: What It Is and Its Genuine Strengths
A monolith is a single application that handles multiple functions — user authentication, data processing, API endpoints, background jobs, and user interface — in a single codebase that’s deployed as a single unit. When you update the authentication logic, you redeploy the entire application; when you fix a bug in the data processing, you redeploy everything together. The entire application runs as one process (or a small number of replicated processes).
Monolithic architecture’s strengths are most apparent in early-stage projects and small teams. In-process function calls are faster than network calls between services. Testing the full application flow requires running one service, not coordinating multiple. Debugging follows a single execution path rather than tracing calls across service boundaries. Deployment is simpler. Data consistency is easier when all data operations run in the same process and the same database transaction. For a team of 1-10 developers building a product that’s still finding product-market fit, monolithic architecture’s simplicity produces faster iteration than microservices’ complexity allows.
Microservices Architecture: What It Is and When It’s Justified
Microservices decompose an application into small, independently deployable services, each responsible for a specific business capability and communicating with others via network calls (typically HTTP/REST or message queues). The checkout service, the user service, the inventory service, and the notification service are separate deployments that can be developed, deployed, and scaled independently.
Microservices are justified when specific problems emerge at scale that monolithic architecture doesn’t solve well: different parts of the application have different scaling requirements (the video processing service needs 50 instances during peak upload periods; the user service needs 3), different teams need to deploy their components independently without coordinating with other teams (Conway’s Law: organisations design systems that mirror their communication structures), or different components need different technology stacks because of specific performance or library requirements.
The Distributed Systems Tax
Every microservices decomposition introduces operational complexity that monolithic architecture doesn’t have: network calls between services can fail, be slow, or produce inconsistent results in ways that in-process function calls don’t. Service discovery (how does service A find service B’s current address?), distributed tracing (how do you trace a request that touches 8 services?), eventual consistency (how do you handle data that’s updated in one service but not yet reflected in another?), and deployment coordination (deploying a change that requires simultaneous updates to 3 services) are all problems that monolithic architecture doesn’t have and that microservices architecture introduces.
This ‘distributed systems tax’ is significant. The team that moves from a monolith to microservices to solve a specific scaling problem often discovers they’ve traded one scaling problem for five operational complexity problems. Microservices are the right solution for the problems they solve at the scale that justifies them; they’re the wrong solution when applied to problems that the monolith was handling adequately.
The Right Sequence
The architecture progression that consistently produces the best outcomes: start with a well-structured monolith (the ‘modular monolith’ where the codebase is organised into clear modules with defined interfaces between them, even though they deploy together), then extract specific services when a genuine scaling or team independence need emerges that justifies the operational overhead of a separate service.
The ‘extract when it hurts’ approach produces microservices where the benefit is real (the specific service that needs independent scaling, the specific team that needs deployment independence) rather than microservices everywhere (because microservices are what modern applications are supposed to use). Most successful technology companies started as monoliths and added microservices strategically as they scaled; the projects that started as microservices before demonstrating product-market fit frequently cite the operational complexity as a significant drag on early development velocity.