| Pattern | Group | What it does | Cost to plan for | Planning use |
|---|---|---|---|---|
| Database per service | Decomposition and data | Each service has a private database that no other service touches | Cross-service queries get harder; cross-table joins and foreign keys are lost | Choose it when service autonomy matters more than cross-service SQL |
| API gateway | Integration | Single entry point; handles authentication, rate limits, TLS termination, response caching and protocol translation | Adds a network hop; a single point of failure if only one instance runs | Run it redundantly and keep clients away from direct service calls |
| Service discovery | Integration | Instances register on start and de-register on stop | Adds infrastructure; the registry becomes a critical dependency that needs health checks | Budget for registry monitoring from day one |
| Event-driven messaging | Integration | Services publish and consume events through a message broker | Trades simple request-reply for eventual consistency | Use it where callers can live with eventual consistency |
| Circuit breaker | Resilience | Stops calls to a failing service so callers are protected while it recovers | Extra error-handling paths; thresholds and timeouts need careful tuning | Put it on calls to dependencies that can fail |
| Saga | Consistency | One of the patterns named for keeping data consistent across services | Consistency becomes an explicit design task because joins are gone | Consider it when one operation spans several services’ data |
The effects and trade-offs above follow the System Design newsletter’s overview of microservices design patterns.
Microservices architecture patterns fall into decomposition, integration and resilience groups. Pick each one for a specific problem you have, and expect every pattern to add a cost somewhere else.
For the wider engineering context, see our software development guide. Changes to service boundaries and API contracts deserve careful scrutiny, which What Is Code Review? A Practical Guide For Developers (2026) – Interestingdevelopment explains. Where these decisions sit in delivery is covered in Phases Of The Software Development Life Cycle: A Practical 2026 Guide To Building Reliable Software – Interestingdevelopment.
Decomposition: boundaries and data ownership
Decomposing a monolith starts with finding the parts worth separating, not with cutting everything at once. The Contentstack guide to microservices design patterns frames the first step as looking for what you can improve in the old system and which services need to be broken up. The System Design newsletter lists Decompose by Business Capability alongside Saga and Health Check API, so splitting along what the business does is the standard starting point.

Each resulting microservice runs as a separate process and talks to others through well-defined tools such as HTTP-based APIs, according to the same Contentstack guide. That makes the interface the real boundary, and it should be treated as a contract.
- Split where the pain is. Begin with the parts of the monolith that need improving or breaking up, and leave stable areas alone until a concrete problem justifies moving them.
- Give each service a private database. The database-per-service pattern means no other service touches that data directly, so a change to one schema cannot silently break another team’s service.
- Accept the lost joins. Once data is split, queries that span services get harder and cross-table joins and foreign keys disappear. If a screen constantly needs data from two services, that is a signal the boundary may be wrong.
Integration: gateway, discovery and messaging
Integration patterns decide how clients reach services and how services reach each other. Each one removes a coupling problem and adds an operational component that must itself be run.
API gateway
An API gateway is the single entry point for your services, and clients should not call services directly. The System Design newsletter says it centralizes cross-cutting concerns: authentication, rate limits, TLS termination, response caching and protocol translation. It suits systems where many services sit behind one public API and web and mobile apps need a single endpoint.

The cost is an extra network hop, and a gateway running as only one instance becomes a single point of failure. Run it redundantly. For .NET teams, Brilworks notes the Ocelot library covers routing, request aggregation and authentication.
Service discovery
Service discovery keeps callers from hard-coding addresses. Per the newsletter, each instance registers its address with a service registry when it starts and de-registers when it stops. Lookup can be client-side, where the caller queries the registry and load-balances itself, or server-side, through a load balancer or the platform.
The trade-off is more infrastructure. The registry becomes a critical dependency and needs health checks to stay accurate. Choose the server-side style when you would rather keep lookup logic out of every service, and the client-side style when callers need control over balancing.
Event-driven messaging
In event-driven messaging, services publish and consume events through a message broker. It trades simple request-reply for eventual consistency. That makes it a good fit where a caller does not need an immediate answer, and a poor fit where users expect to see the result of an action straight away.
Resilience and consistency
Resilience patterns limit how far one failure travels, and consistency patterns deal with the data problems that splitting a system creates.
Circuit breaker
A circuit breaker temporarily stops calls to a failing service, giving it time to recover and protecting callers, as the System Design newsletter describes. When failures cross a threshold the breaker opens and every call fails fast without touching the failed service. After a cool-down it goes half-open and lets one trial call through. Brilworks adds that this prevents a single point of failure from cascading through the system.
The breaker acts as a proxy that a microservice receives requests through, and the dev.to write-up of the pattern points out the cost: it adds a layer every request must pass through, which affects performance. The newsletter also warns of extra error-handling paths and careful tuning of thresholds and timeouts. Adopt breakers on calls to dependencies that can plausibly fail, then tune them against observed behaviour rather than copying defaults.
When to use the saga pattern
Use the saga pattern when a single business operation has to change data owned by more than one service. The newsletter states that keeping data consistent across services needs patterns such as Saga, API Composition and Transactional Outbox. That need exists because database per service removes the joins and foreign keys a monolith relied on.
If an operation touches only one service’s database, no saga is needed. If services merely need to read each other’s data, API Composition is the named alternative. Because event-driven messaging already brings eventual consistency, teams that choose it should expect to design consistency deliberately rather than inherit it.
Choosing what to adopt first
Adopt patterns in response to symptoms, not as a checklist. The decision usually turns on which problem is hurting now.
- Clients juggle many endpoints. Add an API gateway, and plan more than one instance from the start.
- Services call fixed addresses. Introduce service discovery, and commit to health checks for the registry.
- One slow dependency drags callers down. Add a circuit breaker on that call before applying it everywhere.
- Teams edit each other’s tables. Move to database per service and accept the loss of cross-table joins.
- One operation spans several services. Evaluate a saga, or API Composition if the need is only reading data.
- Callers do not need an immediate answer. Event-driven messaging fits, with eventual consistency as the price.
Wait on patterns whose cost you cannot yet operate. A registry, a broker and a gateway are each components to run, so adding all of them at once multiplies what can break.
Frequently asked questions
Which tools implement circuit breakers and gateways?
The System Design newsletter names Resilience4j for Java, Polly for .NET and the Envoy proxy as breaker implementations. Brilworks describes Polly as a transient-fault-handling .NET library, and names Ocelot for gateway features in .NET.
How do microservices communicate with each other?
Each microservice runs as a separate process and communicates through well-defined tools such as HTTP-based APIs. Services can also publish and consume events through a message broker.
What does a circuit breaker save when a service is down?
Without a breaker, a call to a failing service waits for its timeout. In the dev.to example with a timeout of 10 seconds, the user learns about the error only after 10 seconds. A breaker that is open fails fast instead.



