TL;DR — default to a modular monolith
Default to a modular monolith: one deployable app with clean, enforced domain boundaries. It fits most web applications, including B2B SaaS, marketplaces and enterprise portals. Move to microservices only when you have a concrete reason. That usually means 20+ engineers, per-domain scaling profiles that have genuinely diverged, or independent deploy cadences a monolith cannot express, and it typically shows up above roughly 10M requests per day.
The architecture debate of 2016–2020 promised that monoliths were dead and microservices were the future. Hard operational experience has largely corrected that. Here is the short version:
- Default to a modular monolith. Clean modules, enforced domain boundaries, a single deploy pipeline. This is the right starting point for the vast majority of web applications, including B2B SaaS, marketplaces and enterprise portals.
- Extract services when you have a concrete reason. Different scaling profiles, independent deployment cadences, or team-ownership boundaries that a monolith cannot express cleanly. Not before.
- Full microservices make sense at scale. Think 20+ engineers, 10M+ requests per day, and service SLAs that genuinely diverge. Below that threshold, the overhead just taxes your team's velocity.
- A plain monolith is not shameful. Shopify, Stack Overflow and Basecamp shipped at billions of dollars in revenue on well-tuned monoliths. The architecture is only wrong if it is stopping you from doing something you need to do.
The three options defined
Traditional monolith
A single deployable application. All business logic, data access and presentation live in one codebase and one process. Every feature ships together, the database is shared, and scaling means running more copies of the whole application. A classic Rails app is a monolith; so is a Django project or a Spring Boot service.
Modular monolith
Still a single deployable binary, but the code is partitioned into well-defined modules. Each module owns its domain logic, its database schema namespace and its public interface. Modules talk to each other through in-process APIs or message contracts rather than HTTP calls. The codebase deploys simply, yet it is structured so you can pull a module out into its own service later. This is what we reach for first when we build our web application development service engagements for clients in the US and EU.
Microservices
A collection of independently deployable services. Each one owns a narrow domain and talks to the others over HTTP or a message broker (Kafka, RabbitMQ, SQS). Each also carries its own database, its own CI/CD pipeline and its own operational footprint. Do this well and large organisations ship fast without stepping on each other. Do it too early and you get a distributed monolith: all the drawbacks of both worlds, none of the advantages of either.
What a modern monolith can actually do
The idea that "monolith equals legacy" is mostly a marketing artefact of the Kubernetes era. So let us be precise about what a modern monolith can and cannot do.
They scale horizontally
Run four copies of a Rails or Django app behind a load balancer and you are already scaling horizontally. That works until the database becomes the bottleneck. At that point you reach for read replicas and connection pooling, not necessarily a new service. Stack Overflow serves billions of pageviews on nine on-premise servers. The monolith was never the bottleneck there; the real culprits were missing caches, missing indexes and loose query discipline.
They support fast iteration
A monolith has one deploy pipeline, one set of integration tests, and one place to grep when you are chasing a bug. For a team of 3–15 engineers, that is a real coordination advantage. Every distributed system you bolt on multiplies the failure modes you have to monitor and the rollback scenarios you have to rehearse.
They support compliance boundaries
GDPR data residency, HIPAA audit logs and SOC 2 controls are easier to implement inside one application than to enforce across a mesh of services. You keep one audit trail, one secrets store and one TLS termination point. See the patterns we use in how to build a multi-tenant SaaS; multi-tenancy is fully achievable inside a modular monolith.
Where monoliths genuinely struggle
There are real limitations, though. If your checkout service has to handle 50x the traffic of your reporting module, scaling the whole app just wastes resources. If your ML inference pipeline runs on completely different requirements (GPU, Python, its own deploy cadence), keeping it in the same process gets awkward. Those are the right reasons to extract a service. Engineering fashion is not.
When do microservices genuinely pay off?
Microservices are the right answer in a handful of scenarios. Here is how to recognise them when you see them.
Genuinely different scaling profiles
If your product recommendation engine takes 1,000 requests per second at peak while your user-settings API takes 5, there is no sense in scaling both together. Once you can measure that gap in production, and not just sketch it in a whiteboard session, pulling the hot path into its own service pays for itself. For how inference-heavy workloads often justify that split, see the 2026 enterprise AI-agent stack.
Independent deployment cadences
When separate product teams need to ship several times a day without coordinating, a single deploy pipeline turns into a bottleneck. That, not raw performance, was Amazon's original reason for microservices: organisational velocity. If your analytics team and your billing team keep waiting for each other's code to stabilise before a release, the architecture has manufactured a human coordination problem that a service boundary would solve.
Isolated fault domains
A catastrophic bug in a monolith takes down the whole application. In a microservices setup, a bug in your notification service does not have to take checkout with it. Circuit breakers, bulkheads and graceful degradation only make sense once you have service boundaries to enforce them at. For high-revenue flows such as payments, the core API and authentication, that isolation guarantee is worth the operational cost.
Regulatory and data-residency boundaries
A US company serving EU customers under GDPR may genuinely need EU-resident data processed in a separately deployed and audited service, not just a config flag inside a shared app. PCI DSS scope isolation works the same way. Cardholder data handled in its own service, behind its own network boundary, is architecturally cleaner than trying to whittle down a monolith's surface area.
Cost, team size and operational burden
Microservices are not free. Every service you add multiplies the infrastructure and staffing cost. Here is an honest accounting.
Infrastructure cost
Each service needs its own compute (container, Lambda or VM), its own database or database namespace, its own secrets-manager wiring, its own load balancer or API gateway routing rule, its own log-aggregation entry, and its own health-check monitor. Run ten services and you are paying for ten of each. On AWS or GCP, a modular monolith often costs 60–80% less in monthly infrastructure than an equivalent microservices mesh carrying the same traffic.
Observability cost
A monolith fails with a stack trace in one log stream. A distributed system fails with partial traces smeared across five services, two async queues and a caching layer. That is why distributed tracing (Jaeger, Tempo, AWS X-Ray), structured log aggregation (Loki, Datadog, CloudWatch) and service-health dashboards stop being nice-to-haves and become a requirement. Budget a dedicated platform engineer plus $2,000–8,000/month in SaaS tooling once a team runs 10+ services.
Team size requirements
Amazon's two-pizza rule (6–10 engineers per service) is the operational floor for keeping a service maintained without constant context switching. Below 20–30 engineers in total, microservices force every engineer to own several services at once, which is exactly the coordination overhead the architecture was meant to remove. For how those upstream architecture calls feed into the product reliability that drives retention, see the SaaS churn-reduction playbook.
| Dimension | Monolith | Modular Monolith | Microservices |
|---|---|---|---|
| Deploy complexity | Low | Low | High |
| Infra cost (same traffic) | Lowest | Lowest | 2–5x higher |
| Observability overhead | Minimal | Minimal | Significant |
| Horizontal scalability | Coarse-grained | Coarse-grained | Fine-grained |
| Independent team deploys | No | Partial | Yes |
| Min. team to run well | 3–5 engineers | 5–15 engineers | 20+ engineers |
| Time to first production deploy | 1–2 weeks | 1–3 weeks | 4–8 weeks |
Scaling a web app the right way
Before you pick an architecture for scale you do not yet have, work through these levers in order. Most applications never need to go past step three.
1. Vertical scaling and query optimisation
Double the database instance size. Add an index to the slow query. Turn on connection pooling (PgBouncer, RDS Proxy). This is free or near-free engineering, and it commonly buys 5–10x of capacity headroom. Most applications that supposedly "need microservices for scale" actually need one database index and a Redis cache.
2. Horizontal application scaling
Run multiple instances of your monolith behind a load balancer. Add read replicas for read-heavy workloads. Use a CDN to offload static assets and cached API responses. A single Rails or Node.js process at 4 vCPU handles ~500 requests/second. Eight instances behind a load balancer handle 4,000. You reach this ceiling slowly.
3. Caching and async queuing
Put Redis or Memcached in front of your hot read paths. Hand anything that does not need to be synchronous to a background job queue (Sidekiq, Celery, Bull): emails, webhooks, report generation, third-party API calls. Moving that work off the request path removes a whole class of slow-request tail latency that makes your p95 look terrible, and it takes no architectural change at all.
4. Extract one service at a time
When one specific hot path is genuinely bottlenecked and you have exhausted the steps above, extract that service with the strangler fig pattern. Route new traffic to the service while the monolith keeps serving the rest, and migrate incrementally. Do not attempt a big-bang rewrite from monolith to microservices; the failure rate is high and the cost is enormous.
Decision matrix
Use this matrix when you are actually making the call. Score each row for the situation you are in now, not for the company you hope to be in three years.
| Criterion | Choose modular monolith if… | Consider microservices if… |
|---|---|---|
| Team size | Under 20 engineers | 20+ engineers across multiple product squads |
| Traffic pattern | Uniform or low-volume today | Measured, divergent peak loads per domain |
| Deploy cadence | One or two teams, coordinated releases | Multiple teams, independent cadences required |
| Compliance isolation | Standard GDPR/SOC 2 manageable in one app | PCI DSS cardholder scope or strict data residency |
| DevOps maturity | No dedicated platform engineer | Platform/SRE team already in place |
| Technology mix | One primary language/runtime | Genuine need for mixed runtimes (e.g. ML GPU service) |
| Fault tolerance requirement | Full downtime acceptable for rare incidents | Partial degradation required (checkout must survive analytics outage) |
FAQ
Should a startup use microservices?
Almost never at the beginning. Microservices multiply operational surface area — service discovery, distributed tracing, independent CI/CD pipelines and a team large enough to own each service. A startup's constraint is shipping product and learning quickly, not infrastructure flexibility. Start with a modular monolith; extract services when a concrete scaling or ownership boundary forces you to.
What is a modular monolith?
A modular monolith is a single deployable application internally divided into well-defined, loosely coupled modules — each owning its own domain logic, database schema namespace and public API surface. It deploys as one process but is structured so that individual modules can be extracted into separate services later with minimal refactoring. It is the sweet spot for most teams under 50 engineers.
When do microservices pay off?
Microservices pay off when: (1) different parts of the system have genuinely different scaling profiles — checkout handles 10x the load of admin; (2) independent teams need to deploy without coordinating releases; (3) a specific service requires a different technology stack, SLA or compliance boundary. If none of those are true today, the overhead of microservices is pure cost.
Are microservices more scalable than a monolith?
Not automatically. A well-tuned monolith on modern cloud infrastructure handles millions of requests per day with horizontal scaling, connection pooling and read replicas. Microservices allow fine-grained scaling of hot paths — but that benefit only materialises when different services genuinely have different traffic shapes. Many teams add microservices complexity before they have the traffic that would justify it.
How big should the team be to run microservices?
Amazon's two-pizza rule is a useful guide: each service should be ownable by a team of 6–10 engineers. In practice you need at least one dedicated DevOps or platform engineer, SRE coverage, observability tooling and enough developers to maintain each service without constant context switching. Below 20–30 engineers total, microservices usually create more coordination overhead than they remove.
Can I migrate from a monolith to microservices later?
Yes — and this is the recommended path. Build a modular monolith with clean domain boundaries from the start, and extracting a service later is a contained effort: move a module's code, split its database tables and add an API contract. The strangler fig pattern — routing traffic incrementally to a new service while the monolith handles the rest — is battle-tested for this migration. Do not design for microservices on day one unless you already have the team and traffic that requires it.
Last updated 4 June 2026. Architecture guidance based on production engagements delivered for US and EU clients between 2022 and 2026. Cost figures are estimates; actual infrastructure spend varies by cloud provider, region and traffic shape.


