Software architecture patterns: Full catalog & how to choose

UX designer workshops

Choosing a software architecture pattern is rarely about finding the 'best' one, it's about matching trade-offs to constraints most teams never state explicitly: deployment cadence, team topology, and failure tolerance. Confusing an architecture style (a broad philosophy, like distributed systems) with a pattern (a concrete, named approach, like CQRS) leads teams to bolt microservices onto problems that layered monoliths solve better.

We've run this decision process across real modernization projects, from strangler fig migrations to full microservices decompositions. This guide catalogs the patterns that matter, with the trade-offs that actually surface in production.

Software architecture patterns: The fast answer

Layered architecture pattern, microservices architecture, and event-driven architecture cover most production systems, but the pattern name matters less than the constraint it solves for: team size, request latency, and deployment frequency. Get that selection wrong early and no later refactor fully removes the cost.

Our architecture team has worked through strangler fig migrations and microservices decompositions across client engagements, tracking deployment frequency and throughput before and after each rebuild; the pattern that survives contact with production is rarely the trendiest one.

Enterprise architecture research points to steady movement toward microservices and event-driven architecture across mid-market IT estates: 74% of organizations are currently using microservices architecture, with 23% more planning to adopt soon (Akamai, on event-driven microservices architecture).

This overview maps each software architecture pattern, including CQRS, serverless architecture, the microkernel pattern, and the client-server pattern, against team size, scale, and total cost of ownership, so you can shortlist by constraint rather than by name recognition. For a concrete example, Fluent Commerce's event-driven architecture shows how these trade-offs play out in high-volume order and inventory management.

What is software architecture, and how is it different from design?

Software architecture and software design answer different questions, and conflating them is why teams argue past each other in review meetings.

Architecture covers the structural decisions that are expensive to reverse: how services communicate, where state lives, how a system partitions into deployable units. A client-server pattern is architecture, it fixes which side owns which responsibility for the life of the system. Domain-driven design, an icon of modern software architecture, sits one layer down.

It is a design discipline for modeling the domain inside whatever architectural boundaries you've already chosen, not a strategy for drawing those boundaries.

You can run domain-driven design inside a monolith, behind a client-server pattern, or across a microservices architecture. The modeling discipline stays largely the same; the wiring around it doesn't.

Chris Richardson's microservices.io pattern catalog lists more than 40 named patterns split across decomposition, data management, and communication concerns, a reminder that "architecture pattern" is not one category but several, and pulling a pattern from the wrong bucket is a mistake we catch often in early design reviews.

Our working rule: architecture is the contract a team can't cheaply break after month six. Design is everything negotiable inside that contract.

Architecture styles vs. Architecture patterns: What's the difference?

An architecture style is the broad organizing philosophy for how a whole system communicates and partitions state: layered architecture, microservices, event-driven architecture, client-server, serverless. A pattern is a specific, reusable approach to one recurring problem inside that style.

Hexagonal architecture is where developers get this confused most often. Half the blog posts call it a "microservices pattern," but it's actually a style choice about isolating domain logic from infrastructure adapters like databases, message queues, or cloud APIs.

Picture a payments service. The core business rules for validating a transaction live untouched at the center, while adapters for Stripe, a Postgres database, and a Kafka queue plug in around the edges. You can run that same hexagonal shape inside a monolith, a single microservice, or a serverless function.

Compare that to the microkernel pattern, CQRS, the strangler fig pattern, or the circuit breaker pattern. Each solves one narrow problem, plugin extensibility, read/write separation, incremental migration, cascading failure, inside whatever style your team has already committed to.

Conflating the two has real operational cost. Teams that treat "microservices" as a checklist of patterns rather than a style decision end up shipping every software feature through unnecessary network hops, adding latency and deployment risk that automation and better tooling can't fully offset later.

Martin Fowler's writing on software architecture draws this line explicitly: style is the shape of the whole system, pattern is the tool you reach for once that shape is fixed.

Gartner's enterprise architecture research consistently flags terminology confusion between architecture styles and patterns as a recurring source of scoping errors in modernization planning, a gap worth closing before scoping any migration or adding new features to a legacy estate.

12 software architecture patterns, with pros, cons, and use cases

Twelve software architecture patterns cover most production decisions: layered architecture pattern, microkernel pattern, CQRS, MVC, and eight more, each trading one constraint for another. The right pick depends on team size, latency budget, and how often the domain changes under load, not on which pattern is trending.

Pattern Best For Main Trade-off
Layered architecture pattern Small teams, CRUD-heavy admin systems Change ripples across layers as the codebase grows
MVC UI-heavy monoliths, fast prototyping Controllers bloat without discipline
Microkernel pattern Products with a stable core and variable plugins Plugin API becomes a second product to maintain
Client-server pattern Simple request/response systems Server becomes a bottleneck at scale
Microservices architecture Independent scaling, large autonomous teams Distributed debugging, network latency, deployment overhead
Event-driven architecture Asynchronous workflows, high fan-out Eventual consistency complicates reasoning about state
CQRS Read-heavy systems with divergent query and transaction shapes Two models to keep in sync, more moving parts
Saga pattern Distributed transactions across services Compensating logic is hard to test exhaustively
Circuit breaker pattern Protecting callers from a failing downstream service Tuning thresholds wrong causes false trips
Strangler fig pattern Migrating a monolith without a rewrite Migration drags on if scope isn't fenced
Serverless architecture Spiky, event-triggered workloads Cold starts and vendor lock-in
Ports-and-adapters (hexagonal) pattern Testable domain logic isolated from infrastructure Extra abstraction for simple CRUD apps

The layered architecture pattern still wins for teams under fifteen engineers running an internal tool or an admin console. It divides cleanly into presentation, business logic, and data access, and every new hire understands it in a day. The failure mode shows up later: as the domain grows, changes ripple through every layer because nothing forces isolation between them.

MVC solves a narrower problem, separating what the user sees from what the system does, and it works well until controllers start absorbing business logic that belongs elsewhere.

CQRS, by contrast, exists specifically for systems where read and write shapes diverge enough that one model can't serve both efficiently; Martin Fowler's original CQRS write-up is still the clearest definition of when that split pays for itself.

The microkernel pattern, sometimes called plugin architecture, fits products with one stable core and many optional extensions, IDEs, CMS platforms, rules engines. Chris Richardson's microservices.io pattern catalog documents the sibling patterns (saga, circuit breaker) that microkernel systems often need once plugins start calling external services.

Total cost of ownership tracks team topology more than technology choice. A five-person team running full microservices architecture typically spends more of its capacity on operational overhead than the same team on a layered architecture pattern would. Gartner reports that microservices typically cost more to build than monolithic architecture (Gartner, Smarter With Gartner).

We've applied the strangler fig pattern on monolith-to-microservices migrations where fencing scope early made the difference between a six-month cutover and one that stalled.

Microservices vs. Monolithic architecture: Decomposition trade-offs

Microservices architecture wins on independent deployability and team autonomy. Monolithic architecture wins on latency, transactional simplicity, and total cost of ownership for anything under roughly 15-20 engineers.

The decomposition trade-off isn't services versus no services. It's how much operational surface a team can carry, and how many developers are available to own that surface once it exists.

We rarely recommend a rewrite. The strangler fig pattern, documented by Martin Fowler and cataloged alongside decomposition strategies on Chris Richardson's microservices.io, routes traffic through a facade that peels functionality off a monolith module by module.

Legacy paths stay live until traffic is fully cut over, so rollback is a routing change, not a redeploy.

The mechanics matter more than the label. Start by mapping bounded contexts against actual data ownership, not org charts: find tables and modules that change together, isolate the seams where coupling is already loose, and extract the highest-churn context first. Every software team we've worked with underestimates how much of this is data migration, not code extraction, since shared databases are the real coupling point.

The decision matrix comes down to three variables:

Variable Favors monolith Favors microservices architecture
Team size Under 20 engineers, one codebase owner 50+ engineers, multiple domain teams
Latency budget Sub-10ms internal calls, no network hop tolerance Async, event-driven paths acceptable
Change frequency Stable domain, infrequent deploys High-churn domains needing independent release cadence

According to a Camunda-cited survey, 62% of organizations cite managing inter-service dependencies as a top microservices challenge (OpsLevel, challenges of implementing microservice architecture).

Once a service boundary is wrong, the fix is expensive. A wrong cut means chatty inter-service calls, distributed transactions nobody wanted, and a circuit breaker pattern bolted on to mask what should have stayed one deployable unit.

This is also where cloud automation pays off or backfires. Automated pipelines make it cheap to deploy new features across a dozen services, but they also make it cheap to ship a bad boundary a dozen times before anyone notices.

Our practice is to decompose only where a bounded context has proven, measured churn, not on an org chart guess.

Event-driven architecture and distributed systems patterns

Event-driven architecture decouples services by routing state changes through a message broker instead of direct calls. This is the pattern that turns a distributed system from merely split into something that survives partial failure, which is the resilience gap most microservices guides skip.

Once services talk through events, cross-service transactions stop being atomic. The saga pattern replaces two-phase commit with a sequence of local transactions and compensating actions, a design Chris Richardson's microservices.io catalog documents in more depth than most vendor blogs bother with. We've used choreography-based sagas on order-fulfillment flows where a single failed payment step needs to unwind three downstream writes without locking the whole chain.

Resilience patterns matter more once the network is the dependency graph. The circuit breaker pattern trips after repeated downstream failures, described precisely in Martin Fowler's original write-up, stopping a slow payment service from cascading into every service that calls it. The bulkhead pattern isolates thread pools and connection limits per dependency, so one overloaded queue consumer doesn't starve the rest of the fleet.

A service mesh (Istio, Linkerd, or Red Hat's OpenShift Service Mesh) pushes circuit breaking, retries, and bulkheading into the infrastructure layer instead of application code, which is why teams past roughly 20 services adopt one rather than hand-rolling resilience per service. 68% of IT leaders plan to increase their usage of event-driven architecture (Gartner, Maturity Model for Event-Driven 2024).

That operational overhead doesn't disappear once the mesh is deployed, either, which is why many teams pair this shift with dedicated support for ongoing software maintenance needs.

None of this is free. Every message broker adds an operational surface, schema evolution, dead-letter queues, ordering guarantees, that a synchronous monolith never had to solve.

Serverless architecture: Cost model and cold-start trade-offs

Serverless architecture shifts cost from fixed infrastructure to per-invocation billing, which helps at low, spiky traffic and hurts once request volume gets steady and high. An API gateway sits in front of the functions, handling routing, throttling, and auth so the compute layer stays stateless.

That split is also where the cold-start tax lives: the API gateway can respond in milliseconds, but a function that hasn't run recently needs a fresh container spun up before it processes anything.

Cold starts run anywhere from tens of milliseconds to several seconds depending on runtime and package size. Compiled runtimes (Java, C#) typically add 1.2-5+ seconds; interpreted runtimes (e.g., Node.js) add roughly 200-500 ms (EdgeDelta, on AWS Lambda cold starts).

JVM-based Spring Boot cold starts on AWS Lambda commonly exceed 3-5 seconds without GraalVM native compilation, while Go and other compiled-native runtimes tend to start well under a second; see our backend frameworks comparison for the full picture.

For a customer-facing checkout flow, that's the difference between a pattern that works and one that quietly bleeds conversions.

We've moved latency-sensitive endpoints off serverless and back onto provisioned containers on more than one migration, keeping serverless for the async, bursty workloads it actually suits: report generation, webhook processing, scheduled jobs.

The decision matrix we use is simple: team size under ten and unpredictable load favor serverless; steady traffic above a few hundred requests per second, or sub-100ms latency requirements, favor a standing service behind the same API gateway.

Total cost of ownership tells the real story here, not the per-request price. Serverless removes ops overhead but adds monitoring complexity across hundreds of short-lived functions, and that operational cost rarely shows up in the pricing calculator.

Enterprise vs. Application-level architecture patterns

Enterprise architecture patterns govern how systems talk to each other across an organization; application-level patterns govern how one service is built internally. Confusing the two is the most common architecture mistake we see in decomposition reviews. This distinction matters most in enterprise retail and B2B platforms, where teams often need to redesign flexible commerce ecosystems without disrupting internal service boundaries.

The client-server pattern, layered architecture, and microkernel pattern sit at enterprise scope: they decide how request traffic and deployment boundaries are drawn between systems owned by different teams. CQRS, the strangler fig pattern, and circuit breaker pattern sit inside a single service's codebase, shaping how that service handles state, migration, and failure.

Domain-driven design is the bridge between the two altitudes. Bounded contexts from DDD tell you where enterprise boundaries should fall; the aggregates and invariants inside each context tell you which application-level pattern fits. According to Gartner's 2024 enterprise architecture trends report, organizations that map bounded contexts before choosing a service topology report materially fewer rework cycles during platform modernization.

Skip the mapping step and teams pick CQRS or event-driven architecture for reasons that belong at the enterprise layer, not the application one.

How to choose the right architecture pattern for your project

Choosing an architecture pattern comes down to three variables: team size, scale ceiling, and latency budget. Get those three right before comparing feature lists, and the pattern choice mostly picks itself.

A five-person team building an internal tool rarely needs microservices architecture or event-driven architecture, the operational tax outweighs any benefit.

Hexagonal architecture (ports and adapters) is the better default here: it isolates business logic from frameworks and databases, so a small team can swap a queue for a REST call without touching domain code. Alistair Cockburn's original hexagonal architecture frames this as a testability problem first, a scaling problem second.

CQRS earns its complexity when read and write workloads diverge: high query volume against a catalog, low-frequency writes against orders, for instance. Splitting the query model from the transaction model lets each side scale and cache independently, but it introduces eventual consistency your team has to reason about on every feature.

Team size Scale need Latency budget Fit
<10 devs Low-medium Relaxed Layered or hexagonal
10-50 devs Medium-high Moderate Microservices, CQRS for hot paths
50+ devs High Tight Event-driven, serverless for bursty load

On total cost of ownership: teams that modernize a legacy monolith usually see the biggest win in how fast a change can roll out, not in raw compute savings. That gap is almost always organizational overhead, not raw compute cost, which is why we weigh team topology before we weigh throughput numbers.

FAQ: Software architecture patterns

What is software architecture and design patterns?

Software architecture defines a system's high-level structure: its components, responsibilities, and communication paths. Design patterns are reusable solutions to problems that recur inside that structure. A layered architecture pattern sets the tiers, while a circuit breaker pattern fixes failure handling within one tier, keeping strategic and tactical decisions distinct. The same principle applies at the interface layer, where design system patterns for consistent UI give teams reusable building blocks for consistent component behavior.

Software architecture patterns vs architecture styles: What's the difference?

Architecture styles describe broad philosophies of system organization, while architecture patterns are concrete, reusable solutions applied inside a style. Distributed systems is a style; saga and CQRS are patterns you apply within it to solve coordination problems. Knowing the difference stops teams from treating a style as a rigid checklist.

What are the top 10 software architecture patterns?

The ten most-cited patterns are layered, microservices, event-driven, microkernel, client-server, CQRS, saga, strangler fig, circuit breaker, and serverless architecture. Each targets a distinct problem, from monolith decomposition to failure isolation and traffic-based scaling. Martin Fowler's architecture writing and Richardson's catalog remain the reference points for definitions and tradeoffs.

Serverless architecture pattern: When does it make sense?

Serverless architecture fits bursty, event-driven workloads with unpredictable traffic, paying per invocation instead of provisioning idle capacity. A webhook processor or nightly ETL job are typical fits. Gartner predicts more than 50% of container deployments will use serverless container management by 2027, up from less than 25% in 2024 (Gartner, Predicts 2025: Container Management Goes Mainstream). It gets costly once workloads run near-continuously, where microservices architecture wins on unit economics.

How do I choose a software architecture pattern for my project?

Match the pattern to team size, expected scale ceiling, and latency budget, since these three variables narrow the shortlist faster than comparing feature lists. A five-person team rarely needs microservices architecture, and unpredictable event-driven traffic suits serverless architecture. Talk to an architect if the tradeoffs still feel unclear before you commit.

Get an architecture review before you commit

A microservices architecture decision is expensive to unwind once services ship, so pressure-test it before your team commits a quarter of engineering time. We run a two-week architecture review: current-state diagram, service boundaries, data ownership, and a load test against your real traffic profile rather than a synthetic one.

We've reviewed builds running on Red Hat OpenShift and self-managed Kubernetes alike, checking circuit breaker placement and rollout cadence before a single service moves, and we record the session like a YouTube walkthrough so absent stakeholders get the same instant answers as the room.

Talk to our team about your architecture, and we'll flag the trade-offs before they become terms in a contract you can't renegotiate.

We're Netguru

At Netguru we specialize in designing, building, shipping and scaling beautiful, usable products with blazing-fast efficiency.

Let's talk business