In This Guide
Key Takeaways
- Start with a monolith: Amazon, Netflix, and Shopify all started as monoliths. Microservices are not a starting architecture — they are a scaling strategy you apply to specific parts of a successful monolith when the monolith's trade-offs become the dominant constraint.
- Microservices solve organizational problems: Microservices are most valuable when you need independent deployment across multiple teams. If one team owns the entire backend, a modular monolith provides almost all the same benefits with far less operational complexity.
- Serverless and microservices are not the same: Serverless (Lambda, Functions) is an execution model. Microservices is an architecture pattern. You can build a microservices architecture on serverless functions, but you can also build a serverless monolith. They address different dimensions of the problem.
- Event-driven architecture scales everything: Decoupling services through events (SQS, Kafka, Pub/Sub) rather than synchronous API calls makes systems more resilient, more scalable, and easier to evolve independently. It also makes debugging harder — plan for distributed tracing from day one.
The most consequential architecture decision in backend engineering is also the one most often made based on hype rather than analysis: should you build a monolith, microservices, or go serverless?
This guide cuts through the debate with honest trade-off analysis. All three architectures are used in production at successful companies. The right choice depends on your team size, your deployment maturity, your organizational structure, and where you are in the product lifecycle — not on which architecture gets the most conference talks.
The Monolith: Better Than Its Reputation
A monolith is a single deployable unit that contains all application functionality. All code runs in the same process, shares the same database, and deploys as a single artifact. In 2026, most successful SaaS companies under $50M ARR run primarily monolithic backends — including Shopify, Basecamp, and Stack Overflow.
Monolith advantages that are consistently undervalued:
- Simple deployment: One artifact to build, test, and deploy. No service orchestration, no distributed deployment pipeline, no container registry.
- Simple debugging: One log stream, one process to attach a debugger to, one codebase to search through. Debugging a distributed system where a request touches 15 services is exponentially harder.
- Simple transactions: Database transactions work across all operations in the monolith. In microservices, transactions that span service boundaries require distributed transaction protocols (Saga pattern) that are significantly more complex.
- Fast iteration: Adding a new feature that touches three domain areas means editing three modules in one codebase. In microservices, it means coordinated changes across three separate repositories, three deployment pipelines, and three service contracts.
The key insight: the monolith's problems (scaling specific components independently, enabling team autonomy, blast radius of a bad deploy) are only problems at a specific scale and organizational structure. Before that threshold, microservices introduce costs without the corresponding benefits.
Microservices: The Trade-Offs Nobody Talks About
Microservices decompose an application into small, independently deployable services that each own a specific business domain and communicate over APIs or message queues. The benefits are real — but so are the costs.
Microservices benefits (when you need them):
- Independent deployability: Team A can deploy the payments service without coordination with Team B's user service
- Independent scaling: Scale the image processing service to 100 instances without scaling the entire application
- Technology flexibility: Use the right language/framework for each service
- Blast radius limitation: A bug in the recommendations service does not take down the checkout service
Microservices costs (that conference talks skip):
- Network latency: In a monolith, a function call takes nanoseconds. In microservices, a service call over the network takes milliseconds. A request that triggers 20 downstream service calls adds 200-400ms minimum.
- Distributed systems complexity: Partial failures, network timeouts, retry storms, and eventual consistency require sophisticated handling that a monolith does not need.
- Operational overhead: 50 microservices means 50 CI/CD pipelines, 50 Kubernetes deployments, 50 sets of monitoring alerts, and 50 log streams to correlate.
- Testing complexity: Integration testing a service that depends on five other services requires either running all five locally, mocking them, or using a contract testing framework.
The Decision Framework
Use this framework for the architecture decision:
Start with a monolith if:
- You have fewer than 20 engineers
- You do not have multiple independent product teams
- You are pre-product-market-fit or early stage
- Your deployment infrastructure is not mature (no containerization, no CI/CD automation)
Consider microservices when:
- Specific services have radically different scaling requirements (the image processing service needs 100x more compute than the user authentication service)
- You have multiple teams who need to deploy independently without coordination
- Specific domain areas need different technology choices (ML inference in Python, high-frequency trading in Go)
- You have mature DevOps infrastructure and observability tooling
Consider serverless when:
- You have event-driven, short-lived workloads (file processing, webhooks, scheduled tasks)
- Traffic is highly variable or unpredictable
- You want to minimize operational burden and maximize developer time on features
Patterns That Work: Event-Driven, CQRS, BFF
Event-driven architecture: Services communicate by publishing and consuming events through a message broker (SQS, SNS, Kafka, Pub/Sub). The order service publishes an "OrderPlaced" event. The inventory service, notification service, and analytics service each subscribe and react independently. No synchronous coupling between services.
Benefits: loose coupling, natural audit log, resilience (consumers can retry), ability to add new consumers without modifying publishers.
Cost: debugging becomes distributed — a request enters the order service and effects appear in three other services later. Distributed tracing (Datadog APM, OpenTelemetry) is essential for event-driven systems.
CQRS (Command Query Responsibility Segregation): Separate the data models for reads (queries) and writes (commands). Optimize the read model for query performance (denormalized, cached) and the write model for consistency (normalized, transactional). Useful for high-traffic applications where read and write patterns have fundamentally different requirements.
Backend for Frontend (BFF): A separate backend service for each frontend (mobile app, web app, partner API). Each BFF aggregates data from multiple downstream services and shapes the response for its specific client. Eliminates the over-fetching problem of shared APIs and gives frontend teams control over their own data layer.
Frequently Asked Questions
Should I use microservices for my new project?
Almost certainly not, unless you already have the organizational structure and DevOps maturity that microservices require. Start with a well-structured modular monolith. Extract services only when you have evidence that a specific part of the system needs independent scaling or independent deployment. Most successful companies started with monoliths and extracted services selectively as they grew.
What is a modular monolith?
A modular monolith is a single deployable unit (monolith) structured with clear internal boundaries and enforced separation of concerns between modules (modular). Each module has its own domain models, services, and database schemas — but they share a single deployment. A modular monolith provides most of the code organization benefits of microservices without the operational complexity. It is also much easier to extract true microservices from a modular monolith than from a big ball of mud.
What is the CAP theorem and why does it matter for backend architecture?
The CAP theorem states that a distributed system can only guarantee two of three properties simultaneously: Consistency (all reads return the most recent write), Availability (every request receives a response), and Partition tolerance (the system operates despite network partitions). Network partitions are unavoidable in distributed systems, so the real choice is between Consistency and Availability. Most systems choose CP (SQL databases with strict consistency) or AP (eventually consistent NoSQL databases). Understanding this trade-off is foundational for microservices and distributed systems design.
How do I handle transactions across microservices?
Transactions that span multiple microservices cannot use traditional database transactions (ACID). Use the Saga pattern: a sequence of local transactions, each of which publishes events or messages to trigger the next transaction in another service. If any step fails, compensating transactions undo the preceding steps. Orchestrated Sagas use a central orchestrator; Choreographed Sagas use events for coordination. Both approaches require careful design of failure handling and idempotency.
Backend architecture decisions shape your career and your product. Get the skills.
Join professionals from Denver, NYC, Dallas, LA, and Chicago for two days of hands-on AI and tech training. $1,490. October 2026. Seats are limited.
Reserve Your SeatNote: Information in this article reflects the state of the field as of early 2026.