Key Takeaways
- Amazon, Netflix, and Shopify all started as monoliths. Microservices are not a starting architecture — they are a scaling strategy applied to specific parts of a successful monolith when the monolith's trade-offs become the dominant constraint.
- Microservices are most valuable when multiple independent teams need to deploy without coordination. 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 thing. Serverless (Lambda, Functions) is an execution model. Microservices is an architecture pattern. They address different dimensions of the problem.
- Event-driven architecture (SQS, Kafka, Pub/Sub) decouples services and makes systems more resilient and independently scalable. It also makes debugging harder — plan for distributed tracing from day one.
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 one artifact. In 2026, most successful SaaS companies under $50M ARR run primarily monolithic backends, including Shopify, Basecamp, and Stack Overflow. The monolith's reputation problem comes from poorly-structured monoliths, not from the architecture itself.
Simple Deployment
One artifact to build, test, and deploy. No service orchestration, no distributed deployment pipeline, no container registry complexity across 50 services.
Simple Debugging
One log stream, one process to attach a debugger to, one codebase to search. Debugging a request that touches 15 microservices is exponentially harder.
Simple Transactions
Database ACID transactions work across all operations. In microservices, cross-service transactions require the Saga pattern — significantly more complex.
Fast Iteration
Adding a feature touching three domain areas means editing three modules in one codebase. In microservices: three repos, three pipelines, three service contracts to coordinate.
"The monolith's problems 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 each owning a specific business domain and communicating over APIs or message queues. The benefits are real — but so are the costs that conference talks tend to skip over.
Microservices Benefits (When You Need Them)
- Independent deployment: Team A deploys payments without coordinating with Team B's users service
- Independent scaling: Scale image processing to 100 instances without scaling the whole app
- Technology flexibility: Python for ML inference, Go for high-throughput trading
- Blast radius limitation: Bug in recommendations doesn't take down checkout
Microservices Costs (Real, Rarely Discussed)
- Network latency: monolith function call = nanoseconds; service call = milliseconds. 20 downstream calls = 200–400ms minimum added latency
- Distributed systems complexity: partial failures, retry storms, eventual consistency require sophisticated handling
- Operational overhead: 50 services = 50 CI/CD pipelines, 50 K8s deployments, 50 alert sets
- Testing complexity: integration testing a service with 5 dependencies requires running all 5, mocking them, or contract testing
Serverless: When Functions Win
Serverless architecture executes code in ephemeral functions triggered by events — S3 uploads, HTTP requests, queue messages, scheduled timers. The cloud provider manages all server infrastructure. Cost is per-invocation rather than per-hour of running capacity.
Perfect For Event-Driven Work
File processing, webhooks, ETL pipelines, scheduled jobs — workloads that are short-lived and triggered by events. Not suited to long-running processes or WebSocket connections.
Variable Traffic Handling
Scales from zero to thousands of concurrent executions automatically. Zero cost when idle. Ideal when traffic is unpredictable or bursty — API endpoints with irregular demand.
Low Operational Burden
No servers to manage, no OS patches, no capacity planning. Developer time stays on features. AWS Lambda's 1M free invocations/month is sufficient for many low-traffic applications indefinitely.
Cold Start Limitation
Functions that have not been invoked recently require a cold start (~200ms for Python/Node, up to 1–2s for JVM). Use provisioned concurrency for latency-sensitive APIs, or schedule warming.
The Architecture Decision Framework
| Condition | Recommended Architecture | Reason |
|---|---|---|
| Fewer than 20 engineers | Monolith | Microservices require team-level ownership to pay off |
| Pre-product-market fit | Monolith | Fast iteration matters more than scale at this stage |
| No mature CI/CD / containers | Monolith | Microservices require DevOps infrastructure to manage 50 deploys |
| Multiple teams needing independent deploys | Microservices | This is the primary use case for microservices |
| Specific component needs 100x scaling | Microservices | Extract that component, leave the rest as monolith |
| Event-driven / short-lived workloads | Serverless | File processing, webhooks, scheduled tasks — Lambda wins here |
| Highly variable / unpredictable traffic | Serverless | Scale to zero when idle; no wasted capacity cost |
Patterns That Work: Event-Driven, CQRS, BFF
Three patterns appear repeatedly in production backend architectures at scale. Each solves a specific problem that grows from distributed systems requirements.
Event-Driven Architecture
Services communicate by publishing and consuming events through a broker (SQS, Kafka, Pub/Sub). The order service publishes "OrderPlaced" — inventory, notifications, and analytics each subscribe and react independently. No synchronous coupling. Natural audit log. Resilient to consumer downtime (retry from queue). Cost: debugging becomes distributed — OpenTelemetry is essential.
CQRS
Separate read and write data models. Optimize the read model for query performance (denormalized, cached). Optimize the write model for consistency (normalized, transactional). Valuable for high-traffic apps where read and write patterns have fundamentally different scale requirements.
Backend for Frontend (BFF)
A separate backend per frontend (mobile app, web app, partner API). Each BFF aggregates data from multiple downstream services and shapes responses for its specific client. Eliminates the over-fetching problem of shared APIs. Gives frontend teams control over their own data layer.
Migrating From Monolith to Microservices
The strangler fig pattern is the safest migration strategy: extract one service at a time, routing requests for that domain to the new service while keeping everything else in the monolith. Never attempt a big-bang rewrite. The pattern that works:
# Step 1: Identify extraction candidate # Choose a domain with clear boundaries, high scaling need, # or independent deployment requirement. # Image processing, notifications, and reporting are common first targets. # Step 2: Define the service interface FIRST # Write the API contract / event schema before any code. POST /images/resize Event: image.uploaded { bucket, key, targetWidth, targetHeight } # Step 3: Build the new service alongside the monolith # Run both in parallel. Route traffic to old path initially. # Step 4: Dual-write phase # Send requests to both monolith and new service. # Compare outputs. Fix discrepancies. # Step 5: Cut over # Route 100% to new service. Keep monolith code for 30 days as fallback. # Delete monolith code after stability confirmed.
Frequently Asked Questions
Should I use microservices for my new project?
Almost certainly not, unless there is already the organizational structure and DevOps maturity that microservices require. Start with a well-structured modular monolith. Extract services only when there is 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. Each module has its own domain models, services, and database schemas — but they share a single deployment. A modular monolith provides most code organization benefits of microservices without the operational complexity. It is also much easier to extract true microservices from a modular monolith than from an unstructured codebase.
What is the CAP theorem and why does it matter?
The CAP theorem states that a distributed system can guarantee only two of: Consistency (reads return the most recent write), Availability (every request gets a response), and Partition tolerance (the system operates despite network partitions). Network partitions are unavoidable, so the real choice is between Consistency and Availability. Most systems choose CP (SQL with strict consistency) or AP (eventually consistent NoSQL). Understanding this trade-off is foundational for microservices design.
How do I handle transactions across microservices?
Cross-service transactions cannot use traditional ACID database transactions. 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 preceding steps. Orchestrated Sagas use a central orchestrator; Choreographed Sagas use events. Both require careful design of failure handling and idempotency.
Backend Architecture Verdict
Start with a well-structured modular monolith. Build it with clear module boundaries, enforced separation of concerns, and a single shared database. Add event-driven communication (SQS, Kafka) when specific workflows benefit from async decoupling. Extract services only when a specific domain has demonstrated a concrete need: independent deployment by a separate team, or radically different scaling requirements. Serverless is a natural complement — use Lambda for event-driven workloads, webhooks, and async jobs without changing the monolith's synchronous paths. The companies that succeed at microservices got there by starting with a monolith, not by starting with microservices.
Backend Architecture + AI Integration in 2 Days
Hands-on training covering cloud architecture, serverless patterns, and AI deployment — live in a classroom.
Reserve Your Seat — $1,490The microservices hype cycle cost the industry a decade of unnecessary complexity.
The industry spent most of the 2010s convincing engineering teams that microservices were the correct default — and spent the 2020s quietly walking that back. DHH's return-to-the-monolith argument at Basecamp, Amazon's published account of consolidating Prime Video from distributed Lambda functions into a monolith (which reduced costs by 90%), and Segment's public post-mortem on their microservices "death star" all point to the same conclusion: organizational complexity, not technical correctness, drove the microservices trend. Small teams building microservices-first were not mimicking Netflix — they were mimicking the PowerPoint slides about Netflix.
Our prediction: the modular monolith will become the explicit default recommendation in most cloud-provider well-architected frameworks within the next 18 months, where today it is either absent or buried. AWS, Azure, and GCP have commercial incentives to promote service proliferation, but the developer experience backlash has become loud enough that their documentation is already hedging. Tools like Railway and Render — which make deploying a single-process app trivially simple — are growing faster than Kubernetes-orchestration consultants, which is a market signal worth noting.
The practical takeaway for anyone learning backend architecture now: invest deeply in understanding how to structure a well-organized monolith, then learn what forces you to extract services (traffic asymmetry, team ownership boundaries, compliance isolation). In that order. Start with the monolith and earn your way to distributed systems — don't inherit the complexity before you've earned the need for it.