Monolith vs microservices: which architecture should you start with?
Start with a monolith. Microservices solve problems that arise at scale — distributed team coordination, independent deployment of large subsystems, and fine-grained scaling of specific components. A startup that builds microservices before it has those problems is paying operational overhead for benefits it does not need yet. Build a well-structured monolith first, identify the boundaries through real usage, then extract services only when the monolith's seams become bottlenecks.
Key Takeaways
- Start with a monolith. The operational overhead of microservices is real and expensive before you have the team and traffic to justify it.
- Microservices solve specific problems: independent team deployment, fine-grained scaling of components at different loads, and technology diversity across subsystems.
- A well-structured monolith with clean internal module boundaries (a 'modular monolith') is easier to migrate to microservices later than a monolith written without those boundaries.
- The 'strangler fig' pattern — gradually extracting services from a monolith — is how most successful microservice migrations happen. Big-bang rewrites rarely work.
- You need to be running Kubernetes or equivalent container orchestration to operate microservices efficiently. If you are not already running that infrastructure, the cost of adding it is a real argument against microservices.
Start with a monolith. That is the answer for most teams, especially at the early stage. Microservices solve problems that appear at scale: independent team deployment of large subsystems, fine-grained component scaling, technology diversity across domains. If you do not have those problems yet, you are paying the operational cost of microservices for benefits you do not need. The engineers who moved Amazon and Netflix to microservices did not start there — they migrated when the monolith became a bottleneck.
The real difference
A monolith is a single deployable unit. All your application code — API layer, business logic, data access — is packaged and deployed together. When you push a change, you deploy the whole application.
Microservices are multiple independently deployable services that communicate over a network (HTTP/REST, gRPC, or message queues). Each service owns its domain, its database, and its deployment pipeline. The order service deploys independently of the payments service, which deploys independently of the notification service.

This independence is the core value of microservices. It means different teams can release different components without coordinating a single deployment. It means you can scale the component under load (say, your video transcoding service) without scaling the components that are not under load (say, your user profile service). It means you can use Python for your ML service and Node.js for your API layer without mixing them in one codebase.
The cost: every benefit of microservices comes with distributed systems overhead. When your order service calls your payments service, you now have network latency, potential network failures, timeout handling, circuit breakers, distributed tracing, and schema versioning to think about — problems that do not exist in a monolith where those two modules call each other directly in memory.
Monolith in practice
A well-built monolith is fast to develop, easy to debug, and straightforward to deploy. When something goes wrong, you look at one set of logs, one error stack, one service. There is no inter-service latency because function calls are in-process. There is no schema versioning problem between services because all your code runs in the same process against the same database.
The key qualifier is "well-built." A monolith without clear internal module boundaries becomes a big ball of mud — everything depends on everything else, and no change is safe. This is where monoliths earn their bad reputation. The problem is not the monolith architecture; it is the absence of internal structure.
A modular monolith addresses this. You build the monolith with clear domain boundaries: an auth module, a billing module, a notifications module. Modules communicate through well-defined interfaces, not by reaching directly into each other's database tables. The result is an application that deploys as one unit but is structured for future extraction if you need it.

Basecamp, Shopify, and Stack Overflow all run on monolith or near-monolith architectures at significant scale. Shopify processes over 3 million requests per minute on a Ruby on Rails monolith. The architecture is not the ceiling; poor engineering within the architecture is the ceiling.
Microservices in practice
Microservices work well when specific conditions exist: multiple independent teams, high scale with components that need different scaling profiles, or strong technology diversity requirements across subsystems.
Netflix operates over 500 microservices, each owned by a small team. Teams deploy their service independently without coordinating with 20 other teams on a release schedule. At Netflix's scale, this independence is operationally essential — a shared deployment cycle for hundreds of services would grind to a halt.
The operational overhead is real. Each microservice needs its own deployment pipeline, its own health monitoring, its own alerting, and its own logging. When a request spans 5 services, debugging a failure requires distributed tracing (Jaeger, Zipkin, or Datadog APM) to understand which service in the chain is responsible. According to a 2024 CNCF survey, 75% of organisations running microservices cite operational complexity as their biggest challenge.

Data management in microservices is particularly difficult. Each service should own its own data store (database per service pattern). Cross-service queries that are trivial SQL joins in a monolith become API calls with consistency management, eventual consistency, and saga patterns for distributed transactions. This is solvable, but it requires engineers with distributed systems knowledge — which is a scarce skill.
Side-by-side comparison
| Factor | Monolith | Microservices |
|---|---|---|
| Deployment complexity | Single deployment unit | Independent per-service pipelines |
| Development velocity (early) | Faster | Slower (setup overhead) |
| Development velocity (at scale) | Slower (coordination overhead) | Faster (independent teams) |
| Debugging | Simple (single logs, single trace) | Complex (distributed tracing required) |
| Testing | Straightforward (one integration test suite) | Complex (contract testing between services) |
| Scaling | Scale the whole application | Scale individual components |
| Infrastructure cost (small team) | Lower | Higher (multiple services, orchestration) |
| Infrastructure cost (large scale) | Potentially higher (cannot isolate hot paths) | Potentially lower (scale only what you need) |
| Inter-component latency | In-process (microseconds) | Network (milliseconds) |
| Team coordination | High (shared deployment cycle) | Low (independent releases) |
| Technology diversity | Limited (shared codebase) | Full (each service picks its stack) |
| Best fit | Teams under 20 engineers, early-stage products | Large engineering orgs, components at different scales |
When to pick a monolith
A monolith is the right starting point when:
Your team is under 20 engineers. Microservices require dedicated platform engineering to manage effectively. Most teams under that threshold do not have the capacity.
You are in the first 12-18 months of a product. Your domain boundaries will change. Features that seem separate today will merge; features you did not plan for will need to split out. Building microservices on unstable domain boundaries means rewriting services early.
Your traffic is not differentiated enough to justify per-component scaling. If your API server, background jobs, and file processing are all under the same load profile, scaling them independently provides no benefit.
You are not yet running container orchestration (Kubernetes, ECS). Without it, deploying and managing dozens of services is a full-time operational job.
Build a modular monolith: enforce clean module boundaries, own each domain within a well-defined interface, and structure the codebase so extraction is straightforward when the time comes.
When to pick microservices
Microservices are the right call when:
You have multiple teams that need to deploy independently. If team A's release cycle is blocked by team B's stability issues, independent deployment becomes a genuine business need.
Specific components have dramatically different scaling requirements. Your image processing service needs 100 GPU instances at peak; your auth service needs 2 standard instances at all times. Packing them into one monolith means scaling both together.
You have strict technology requirements across domains. Your ML pipeline needs Python. Your API layer is Node.js. Your batch processing is Go. A monolith cannot serve all three.
You are building a new component that needs to be isolated for compliance or security. Payment processing, PII handling, or regulated data storage often belongs in its own service boundary for audit and compliance purposes.
Even then: start with the minimal number of services. "Microservices" does not mean hundreds of services. Three or four well-bounded services is often enough.
What we use at RaftLabs
Most products we ship start as modular monoliths. We build with clear domain boundaries — authentication, core business logic, notifications, billing — as separate modules within a single deployed application. This gives the client fast time to market, simpler infrastructure costs, and a codebase that is easy to understand and maintain with a small team.
We have migrated clients from monoliths to partial microservices architectures as they scaled. The migrations that went well had two things in common: the original monolith had clean module boundaries, and we extracted services incrementally rather than rewriting everything at once. The strangler fig pattern — routing specific functionality to new services while leaving the rest of the monolith intact — is how we approach it.
We have also built full microservices architectures from the start for enterprise clients with large existing engineering teams and specific components that needed independent deployment pipelines. At that scale, with that team size, it was the right call. For a 3-person startup, it would have been the wrong call.
Common mistakes teams make
Premature decomposition. The most expensive microservice mistake is splitting a domain before you understand it. A team that builds a separate "user service" and "profile service" in week two will often discover in week eight that those domains need to share data constantly, and that the network boundary between them causes more problems than it solves. Wait until you have real usage data before drawing service boundaries.
Ignoring the platform engineering requirement. Microservices do not run themselves. You need CI/CD pipelines for each service, container orchestration (Kubernetes or ECS), service discovery, centralised logging, distributed tracing, and a secrets management system. This infrastructure is a real engineering investment. Teams that skip it end up with microservices that are harder to operate than the monolith they started with.
Using microservices to fix organisational dysfunction. Microservices are sometimes proposed as a solution to slow deployments and team coordination problems. They can help with those problems at sufficient scale, but they cannot fix poor engineering practices or unclear team ownership. If your deployment is slow because of poor CI/CD, fix the CI/CD pipeline. If team coordination is broken, fix the team structure. Adding service boundaries to a dysfunctional organisation makes the dysfunction harder to see, not easier to fix.
Frequently asked questions
- Start with a monolith. Microservices introduce operational complexity — service discovery, distributed tracing, network latency between services, independent deployment pipelines — that absorbs engineering capacity that early-stage companies need for building product features. The stack Amazon and Netflix use today is not the right stack for a team of five engineers. Build a clean monolith, ship quickly, and extract services only when specific components need to scale independently.
- Microservices introduce distributed systems problems: network partitions, inter-service latency, distributed tracing complexity, data consistency across services, and independent deployment coordination. Each service needs its own CI/CD pipeline, its own monitoring, and its own error handling for cases where dependent services are unavailable. This operational overhead is manageable at scale with dedicated platform engineering teams but is expensive for smaller teams.
- Yes, and most successful microservice architectures started as monoliths. The strangler fig pattern — gradually extracting high-load or independently deployable subsystems from the monolith into services — is the proven approach. It works best when the monolith was built with clear internal module boundaries. A monolith with tangled dependencies everywhere is harder to migrate than one with well-defined domain boundaries.
- A modular monolith is a single deployable application built with strong internal module boundaries — each domain (auth, billing, notifications, etc.) is a self-contained module with a well-defined interface. It is deployed as one unit but structured as if each domain were a separate service. This approach gives you monolith simplicity while maintaining the internal structure needed to extract services later with less refactoring.
- Netflix runs hundreds of microservices; Amazon runs thousands. These numbers are often cited as evidence that microservices are the right approach. They are not evidence that microservices are right for your product — they are evidence that microservices can be made to work at extreme scale with large dedicated platform engineering teams. Most products will never reach a scale where those architectures are necessary.
Ask an AI
Get an instant summary of this post from your preferred AI assistant.
Related articles

How to build an app like Wise: Cross-border payments architecture explained
Wise moved $118 billion in 2024 on a simple promise - show the real exchange rate and charge a transparent fee. The engineering behind that promise is anything but simple. Here's what it takes to build a cross-border payment app.

Pharmaceutical Software Development: Types, Cost, and Regulatory Requirements in 2026
Pharma software runs on tight regulatory constraints that standard development shops don't understand. Here is what it costs, what FDA and GxP compliance requires, and when custom development beats buying an off-the-shelf LIMS or QMS.

How to build an app like Booking.com: Architecture, features, and real costs
Booking.com is a hotel search and booking engine backed by live inventory from 28 million+ properties. Here's how the property data pipeline, availability engine, and payment flow work -- and what it takes to build something comparable.
