Microservices Design Patterns
Microservices give teams independence — but independence without patterns leads to chaos. Six design patterns solve the most common problems: how clients reach services, how services find each other, how reads and writes scale, how UIs get tailored APIs, how systems communicate asynchronously, and how data stays isolated. Understanding when to use each pattern is what separates a working distributed system from a fragile one.
API Gateway
Clients should not need to know about every microservice behind the scenes. An API Gateway sits at the edge as a single entry point — routing requests from web apps, mobile apps, and third-party consumers to the right service. It centralizes cross-cutting concerns like authentication, rate limiting, and request transformation so individual services stay focused on domain logic.
Takeaway: One front door for clients — many services behind it.
Service Discovery
In dynamic environments, service instances come and go. Hard-coding addresses does not scale. Service Discovery solves this with a registry: each service registers itself on startup, and the API Gateway (or other clients) looks up available instances at request time. The registry becomes the source of truth for what is running and where.
Takeaway: Let services announce themselves — never hard-code endpoints in production.
CQRS (Command Query Responsibility Segregation)
Reads and writes often have different performance and scaling needs. CQRS splits them into separate paths: a Command side handles creates, updates, and deletes through a Command Model, while a Query side handles reads through an optimized Query Model. Both can share storage or use separate stores depending on complexity.
Takeaway: Separate read and write models when load patterns differ.
Backends for Frontends (BFF)
A mobile app and a web dashboard rarely need the same API shape. The BFF pattern gives each client type its own backend layer — a Mobile BFF and a Web BFF — that aggregates and shapes data from underlying microservices. Each frontend gets an API designed for its UX without forcing one generic contract on everyone.
Takeaway: Tailor APIs to the client — one size does not fit all frontends.
Event Driven
Not every interaction needs a synchronous request-response. In event-driven architecture, producers publish events to a message broker when something happens. Consumers subscribe and react independently — updating state, triggering workflows, or notifying users. This decouples services in time and makes systems more resilient to partial failures.
Takeaway: Use events when services should react without waiting on each other.
Database per Service
Sharing one database across microservices creates tight coupling — a schema change in one service can break another. Database per Service gives each bounded context its own private storage. A Video Service owns video data, an Email Service owns email data, and a Notification Service owns its own store. Services communicate through APIs or events, not shared tables.
Takeaway: Own your data — shared databases undo the benefits of microservices.
Final Thoughts
These six patterns are building blocks, not a checklist. Real systems combine them: an API Gateway at the edge, service discovery behind it, BFFs for different clients, CQRS where read/write load diverges, events for async workflows, and isolated databases per service. Pick the patterns that match your constraints — and know why you chose each one.