What is a Monolith?
A monolithic application is a single deployable unit. All functionality — user authentication, product catalog, order processing, payment, notifications — lives in one codebase and is deployed together. Communication between components happens via in-process function calls, not network requests.
Monoliths get a bad reputation, but they have real advantages: simple deployment (one artifact), easy debugging (one process, one log stream), fast in-process communication, and simple transactions (everything in the same database). Many highly successful products are monoliths.
What are Microservices?
Microservices architecture decomposes the application into small, independently deployable services. Each service owns a specific business capability, has its own database, and communicates with others via APIs or message queues.
Side-by-Side Comparison
| Property | Monolith | Microservices |
|---|---|---|
| Deployment unit | One artifact | Many independent services |
| Deployment complexity | Simple | High — CI/CD per service |
| Scaling | Scale entire app together | Scale individual services |
| Communication | In-process function calls | Network (REST, gRPC, events) |
| Data management | Single database, easy JOINs | Database per service, no shared DB |
| Transactions | Simple ACID transactions | Complex (Saga pattern, eventual consistency) |
| Testing | Straightforward integration tests | Complex — services must be stubbed/mocked |
| Debugging | One log stream, one process | Distributed tracing (Jaeger, Zipkin) |
| Team structure | Works for one team | Enables multiple independent teams |
| Technology choice | One language/framework | Each service can use different stack |
| Fault isolation | One bug can crash everything | Failures isolated to one service |
| Operational overhead | Low | Very high (Kubernetes, service mesh, etc.) |
When to Use Microservices
Microservices make sense when:
- Different scaling requirements: Your image processing service needs 100 instances but your user service needs 3
- Multiple teams: You have 5+ teams and want them to deploy independently without coordinating
- Different technology needs: Your ML recommendation service needs Python/GPU; your order service needs Java/PostgreSQL
- Clear domain boundaries: Your domain is well understood and service boundaries are stable
- Fault isolation requirements: A failure in notifications must never impact order processing
Conway's Law
Organisations design systems that mirror their communication structures. If you have 5 teams, you will naturally tend toward 5 services. Microservices and team structure should align — one team per service is the ideal. If one team owns all the services, the benefits of microservices largely disappear.
When to Stay with a Monolith
- New product: You don't yet know the right boundaries. Start with a monolith, then extract services when boundaries become clear.
- Small team: Microservices operational overhead can consume a small team's entire capacity
- No scale issue: If your monolith handles load fine, you're solving a problem you don't have
- Greenfield startup: Move fast, validate the business, then refactor. Shopify processed billions in sales as a monolith.
Beware the Distributed Monolith
The worst outcome is splitting your app into microservices but keeping them tightly coupled — shared databases, synchronous call chains, deploying multiple services together. This gives you all the operational complexity of microservices with none of the benefits. Before splitting, ensure each proposed service can operate independently.
Common Microservices Patterns
API Gateway
A single entry point for all clients. The gateway routes requests to appropriate services, handles authentication, rate limiting, and SSL termination. Clients never talk directly to internal services. Examples: AWS API Gateway, Kong, Nginx.
Event-Driven Architecture
Services communicate asynchronously through events (Kafka, RabbitMQ). The Order Service emits an "OrderPlaced" event; the Notification Service and Inventory Service consume it independently. Services are decoupled — they do not need to know about each other.
Circuit Breaker Pattern
If Service A calls Service B and B is slow or failing, the circuit breaker "opens" after a threshold of failures — returning an error immediately instead of letting calls pile up. This prevents cascading failures. Libraries: Resilience4j (Java), Polly (.NET), Hystrix (Netflix, deprecated).
Strangler Fig Migration
The recommended way to migrate from monolith to microservices: gradually extract services one at a time. New features go into new services. Old monolith code is replaced piece by piece. The monolith "strangles" over time without a risky big-bang rewrite.
The Modular Monolith — The Middle Ground
A modular monolith is the best of both worlds for many teams: one deployable application, but with rigidly enforced internal module boundaries. Each module has its own models, services, and database tables — with no direct cross-module database queries. Modules communicate through well-defined interfaces.
This gives you: easy development and testing (monolith), clear domain boundaries (ready to extract services when needed), and simple deployment. Shopify's Rails monolith is a famous example. When you need to extract a service, the module boundary already exists.
How We Research and Update This Guide
We test the underlying formula or workflow, compare outputs with reliable references, and revise examples whenever the page content changes.
- The workflow or formula is tested directly in the tool and compared against independent reference examples.
- Examples are kept practical so readers can verify the result without hidden assumptions.
- Pages are revised whenever the interface, calculation flow, or surrounding guidance materially changes.
Frequently Asked Questions — Microservices vs Monolith
Microservices is an architectural style where an application is built as a collection of small, independent services — each responsible for a specific business capability (User Service, Order Service, Payment Service). Each service has its own codebase, database, and deployment pipeline. Services communicate via APIs (HTTP/REST, gRPC) or events (Kafka, RabbitMQ). Contrast with a monolith: all functionality in one deployable unit.
Independent scaling — scale only the services under load (e.g. scale the Image Processing service without scaling the User service). Independent deployment — deploy the Payment service without touching or redeploying the rest of the app. Technology flexibility — each service can use the best language/database for its job. Fault isolation — a crash in the Notification service does not take down the entire application. Team independence — teams own services end-to-end.
Network latency — what was an in-process function call is now a network request. Distributed systems complexity — partial failures, eventual consistency, distributed transactions. Operational overhead — each service needs its own CI/CD, monitoring, logging, health checks. Testing complexity — integration testing across services is harder than testing a monolith. Data management — each service owning its database means cross-service queries require APIs or event streams, not SQL JOINs.
Do not start with microservices for a new product. You do not yet know the right service boundaries — premature decomposition creates the wrong boundaries, which are painful to change. Start with a well-structured monolith ("modular monolith"). Extract services only when you have a clear scaling need (one part needs to scale independently) or organisational need (separate teams owning separate domains). The worst outcome is a distributed monolith — microservices with all the operational complexity but tight coupling between services.
A distributed monolith has the worst of both worlds: it is split into separate deployable services (microservices operational complexity) but the services are tightly coupled — changing one requires changing others, deploying them together, or they fail if one is down. This happens when services share databases, make synchronous calls to each other in chains, or are split by technical layer (frontend service, backend service) rather than business capability. Avoid it by ensuring each service owns its data and can operate independently.
Netflix: 500+ microservices, pioneered many patterns (circuit breaker, chaos engineering). Amazon: "two-pizza teams" — each team owns a service small enough for two pizzas to feed. Uber: 2,000+ microservices. However, many successful companies use monoliths or hybrid approaches: Shopify (Rails monolith that handles massive scale), Stack Overflow (monolith), Basecamp (monolith). The architecture should fit your team and problem, not follow hype.