Somebody on your team is about to say "we should probably do microservices" in a planning meeting, and the meeting will lose an hour to it.
Here's the thing nobody says out loud in that meeting: there are at least ten legitimate architectures, microservices is not automatically the adult choice, and the pattern that wins is whichever one matches your actual failure modes — not the one with the best conference talks.

This is a field guide, not a ranking. Each pattern gets a fair shot and an honest "here's where this bites you."
1. Monolithic
A monolith is the simplest physical architecture: one deployable artifact, one runtime process, one database, one release cadence. The application’s user interface, domain logic, and data access all live inside a single codebase.
Architecture details:
- One process or set of process replicas.
- One shared database schema.
- Shared memory and local method calls are the norm.
- Cross-cutting concerns like auth, logging, and metrics are centralized.
Example: - A B2B SaaS product built by a three-person team where the web UI, API endpoints, and backend services all ship together in a single container image.
- A CRUD inventory application with one database and one web server.
When it is right:
- You have a small team and need to move fast.
- The product is still finding product-market fit.
- You want to minimize operational overhead.
- You need a single mental model for the codebase.
What it buys you:
- Lower coordination cost.
- Easier local debugging and end-to-end testing.
- One place to change behavior.
- Cheap and predictable deployment.
When it bites:
- A bug in one area can down the whole application.
- Scaling requires scaling every component together.
- Release cadence becomes a shared constraint.
- The codebase can become a ball of mud if internal boundaries are ignored.
Failure mode:
- The monolith is still the right decision until it isn’t. The worst mistake is splitting too early for scale that does not exist.
2. Microservices
Microservices divide a system into independently deployable services, each owning its own data and business capability. Services communicate over the network rather than through local calls.
Architecture details:
- Each service has its own database and data model.
- Services talk over HTTP, gRPC, message buses, or async APIs.
- An API gateway or service mesh often handles routing, discovery, and cross-cutting concerns.
- Deployments are independent, but observability, tracing, and contract testing become mandatory.
Example: - An e-commerce system where "orders," "inventory," "payments," and "catalog" are separate services.
- A mobile backend where authentication and user profile management are separate microservices.
When it is right:
- Multiple teams need to release independently.
- Components have different scaling characteristics.
- The organization can support the operational cost of distributed systems.
What it buys you:
- Teams can choose technology independently.
- Services can scale on their own.
- Fault isolation between bounded contexts.
- Clear ownership boundaries.
When it bites:
- Cross-service transactions become hard.
- Latency increases due to remote calls.
- Debugging means tracing across service boundaries.
- Schema changes require coordination and contract evolution.
Failure mode:
- A collection of services that must be deployed and released together is a distributed monolith, not a real microservices architecture.
3. Hexagonal (Ports & Adapters)
Hexagonal architecture focuses on separation between business logic and external details. The core application is surrounded by ports, and adapters connect those ports to frameworks, databases, UIs, and external APIs.
Architecture details:
- The core contains business rules and domain logic.
- Input ports define how external actors invoke the application.
- Output ports define how the application sends data out.
- Adapters implement those ports for a specific technology.
- Dependencies point inward toward the core.
Example: - A billing engine where the core handles pricing rules, and adapters manage REST input, CLI commands, a SQL database, and a payment gateway.
- A warehouse dispatch system with the same core logic used for a web dashboard and an event-driven worker.
When it is right:
- You want to protect domain logic from infrastructure changes.
- You expect to swap databases, messaging platforms, or UI frameworks.
- You need fast unit testing without bringing up external dependencies.
What it buys you:
- Clean separation between rules and infrastructure.
- Easier testability of business logic.
- The ability to introduce new delivery mechanisms without rewriting core logic.
When it bites:
- It can feel like overengineering for simple CRUD apps.
- Teams can spend more time defining ports than delivering features.
- New engineers may need a longer ramp-up to understand the adapter pattern.
Failure mode:
- A over-abstracted app where business intent is hidden behind an unnecessary layer of indirection.
4. Event-Driven Architecture
Event-driven architecture centers around events as the primary means of communication. Producers emit events and consumers react independently.
Architecture details:
- An event bus or streaming platform carries events.
- Producers publish facts about things that happened.
- Consumers subscribe and react asynchronously.
- The system often becomes eventually consistent.
Example: - An order system where "order created" triggers payment capture, inventory reservation, shipping label creation, and analytics events.
- A customer data platform where profile updates are published as events consumed by personalization, email, and reporting services.
When it is right:
- Your domain has naturally decoupled reactions to a single event.
- You need to compose independent workflows.
- You want to avoid synchronous coupling between unrelated subsystems.
What it buys you:
- Loose coupling and independent evolution of components.
- Better scalability for fan-out workloads.
- A clear audit trail in the event stream.
When it bites:
- Eventual consistency requires a new operational mindset.
- Debugging is harder because state changes are not centralized.
- You can end up with a tangled event contract surface.
Failure mode:
- Building an entire system around events before you have real asynchronous needs, then suffering from complexity without benefit.
5. Layered (N-Tier)
Layered architecture divides the system into horizontal layers such as presentation, application, domain, and infrastructure. Each layer only communicates with the one directly below it.
Architecture details:
- Presentation layer handles UI and API contracts.
- Application layer orchestrates use cases.
- Domain layer contains business rules.
- Infrastructure layer handles persistence and external systems.
- Dependencies flow downwards.
Example: - A classic enterprise application where the web UI talks to controllers, controllers delegate to services, services execute business logic, and repositories persist entities.
- A banking application with a separate reporting layer that reads from a shared data source.
When it is right:
- Your app is CRUD-heavy and internal-facing.
- You want a common structure that many engineers already understand.
- You need to reduce cognitive overhead for team onboarding.
What it buys you:
- Predictable organization.
- Separate concerns by responsibility.
- Easier enforcement of architectural boundaries.
When it bites:
- Logic can still leak across layers under deadline pressure.
- The pattern can encourage passive domain models and anemic services.
- If not maintained, layers become arbitrary file structure rather than discipline.
Failure mode:
- Allowing business rules to be split across presentation and persistence layers, which erodes the value of the pattern.
6. Clean Architecture
Clean architecture uses concentric circles to isolate entities and use cases from delivery and infrastructure details. Outer layers can depend on inner layers, but not vice versa.
Architecture details:
- Entities at the center represent core business objects.
- Use cases define application-specific operations.
- Interface adapters convert data between domain and external shapes.
- Frameworks and drivers sit at the outermost edge.
- Dependency inversion keeps the core independent.
Example: - A payments service where entities are payment instruments and transactions, use cases are authorize/capture/refund, adapters convert REST, Kafka, and SQL, and frameworks are Spring Boot or Express.
- A healthcare system that separates patient rules from the particular EMR integration.
When it is right:
- You are building a system intended to last for years.
- You expect frequent infra or UI churn.
- You want a strong, enforceable separation between business logic and plumbing.
What it buys you:
- Long-term maintainability.
- A clear path for replacing outer layers.
- Business rules that are easy to test in isolation.
When it bites:
- The additional layers add cognitive overhead.
- Developers can mistake the structure for the point of the architecture.
- The pattern is not worth it for a short-lived MVP.
Failure mode:
- Too much ceremony around interfaces and DTOs, with little value for the actual product.
7. CQRS (Command Query Responsibility Segregation)
CQRS separates the write side from the read side. Commands mutate state with strict validation, and queries read state from a model optimized for fast retrieval.
Architecture details:
- The write model handles business invariants.
- The read model is often denormalized and served by a different database or projection.
- Synchronization may be asynchronous, using events or change streams.
- Commands and queries are distinct entry points.
Example: - An order management system where order placement uses a normalized write database, while dashboards and customer views query a denormalized read store.
- A CRM where lead updates go through commands, and sales dashboards read from optimized summary tables.
When it is right:
- Reads and writes have very different performance or consistency requirements.
- You need different scaling strategies for queries and updates.
- The read side needs complex aggregations that would bloat the write model.
What it buys you:
- Optimized read performance.
- Clear separation of concerns.
- Better scaling for query-heavy workloads.
When it bites:
- It introduces eventual consistency.
- You need infrastructure for projections and event delivery.
- Developers must reason about two models instead of one.
Failure mode:
- Applying CQRS to a simple CRUD application where the complexity outweighs the performance gain.
8. Serverless (Functions as a Service)
Serverless architecture splits logic into small functions that execute in response to events and are managed by a cloud provider.
Architecture details:
- Functions are stateless and short-lived.
- Triggers include HTTP requests, queue messages, timers, or storage events.
- Infrastructure is described declaratively as functions, triggers, and permissions.
- Billing is per execution rather than per machine.
Example: - A webhook processor that runs a Lambda for every incoming event and writes normalized data to a database.
- A nightly report generator triggered by a scheduled event.
When it is right:
- Workloads are spiky and unpredictable.
- You want to minimize ops for low-traffic services.
- You need rapid iteration on small, well-scoped functions.
What it buys you:
- No server management.
- Auto-scaling to zero.
- Fast deployment of isolated behavior.
When it bites:
- Cold-start latency hurts interactive requests.
- Vendor lock-in can grow quickly.
- Local debugging and testing are harder.
- Long-running jobs and stateful workflows are awkward.
Failure mode:
- Treating every endpoint as a separate function without considering end-to-end orchestration and debugging.
9. Pipeline Architecture
Pipeline architecture organizes processing as a sequence of stages. Data flows through extract, transform, and load steps, often with the ability to replay or resume.
Architecture details:
- Stages are typically composable and independently deployable.
- Data is transformed incrementally.
- The pipeline may be batch-based, stream-based, or both.
- Checkpointing and replayability are common requirements.
Example: - A data ingestion pipeline that reads customer events, normalizes them, enriches them with lookup data, and writes them to analytics tables.
- A machine learning feature pipeline that computes training features from raw logs.
When it is right:
- Your work is inherently data processing.
- You need to inspect or replay intermediate outputs.
- Latency is bounded by stage processing, not by user interactivity.
What it buys you:
- Clear separation of data processing concerns.
- Easier debugging of data flow.
- Better reuse of transformations.
When it bites:
- Batch pipelines are not a great fit for low-latency interactive needs.
- Researchers can overfit the pipeline to a particular data shape.
- Failure handling across stages can become complex.
Failure mode:
- Forcing a non-data system into a pipeline shape and paying the cost of stage orchestration without the benefit.
10. Space-Based Architecture
Space-based architecture uses a distributed in-memory data grid to avoid centralized database contention. Application instances share state through a replicated or partitioned in-memory space.
Architecture details:
- The data grid is the hot path for reads and writes.
- The backing database is a persistence store, not the primary runtime store.
- State is partitioned and replicated across nodes.
- The architecture is tuned for low latency and very high throughput.
Example: - A real-time bidding engine where bidder state and offers are stored in-memory across a grid.
- A stock-trading order book that needs microsecond response times and cannot tolerate a single database bottleneck.
When it is right:
- Latency and throughput requirements exceed what a relational database can deliver.
- The system is write-heavy and stateful.
- You have strong operational capability for distributed in-memory systems.
What it buys you:
- Extremely low latency.
- High throughput under load.
- Reduced pressure on a central database.
When it bites:
- Operational complexity is high.
- Data grid partitioning and failure handling are hard.
- It is easy to build the wrong consistency model.
Failure mode:
- Choosing space-based architecture because it sounds fast instead of because you measured the database as the bottleneck.
How to Choose
Architecture is not a checklist of trendy names. It is a set of constraints you choose to live inside.
- Start with the simplest shape that solves your problem.
- Separate physical topology decisions from code-structure decisions.
- Monolith vs microservices is about deployment.
- Hexagonal vs layered vs clean is about code organization.
- Measure the failure modes you need to avoid.
- Do you need independent team releases?
- Do you need low-latency updates?
- Do you need a stable core of business rules?
- Accept that most systems are hybrids.
- A layered monolith with an event-driven order pipeline is a valid, sane architecture.
- A microservice can use hexagonal architecture inside its boundary.
The useful question is rarely "which architecture is best?" It is "what failure mode am I protecting against, and what tax am I willing to pay?"
If you can answer that, you can pick one of these ten with clarity — and avoid the most dangerous architecture of all: the one chosen because it sounds good in a meeting.
Top comments (0)