microservices
Use this skill when designing microservice architectures, decomposing monoliths, implementing inter-service communication, or solving distributed data challenges. Triggers on service decomposition, saga pattern, CQRS, event sourcing, API gateway, service mesh, circuit breaker, distributed transactions, and any task requiring microservice design decisions or migration strategies.
engineering microservicesdistributed-systemsarchitecturepatternsservicesWhat is microservices?
Use this skill when designing microservice architectures, decomposing monoliths, implementing inter-service communication, or solving distributed data challenges. Triggers on service decomposition, saga pattern, CQRS, event sourcing, API gateway, service mesh, circuit breaker, distributed transactions, and any task requiring microservice design decisions or migration strategies.
microservices
microservices is a production-ready AI agent skill for claude-code, gemini-cli, openai-codex. Designing microservice architectures, decomposing monoliths, implementing inter-service communication, or solving distributed data challenges.
Quick Facts
| Field | Value |
|---|---|
| Category | engineering |
| Version | 0.1.0 |
| Platforms | claude-code, gemini-cli, openai-codex |
| License | MIT |
How to Install
- Make sure you have Node.js installed on your machine.
- Run the following command in your terminal:
npx skills add AbsolutelySkilled/AbsolutelySkilled --skill microservices- The microservices skill is now available in your AI coding agent (Claude Code, Gemini CLI, OpenAI Codex, etc.).
Overview
Microservices is an architectural style that structures an application as a collection of small, independently deployable services, each owning its domain and data. Each service runs in its own process and communicates through lightweight mechanisms like HTTP/gRPC or async messaging. The style enables teams to develop, deploy, and scale services independently, reducing coupling and increasing resilience. It trades the simplicity of a monolith for the operational complexity of distributed systems - that trade-off must be made deliberately.
Tags
microservices distributed-systems architecture patterns services
Platforms
- claude-code
- gemini-cli
- openai-codex
Related Skills
Pair microservices with these complementary skills:
Frequently Asked Questions
What is microservices?
Use this skill when designing microservice architectures, decomposing monoliths, implementing inter-service communication, or solving distributed data challenges. Triggers on service decomposition, saga pattern, CQRS, event sourcing, API gateway, service mesh, circuit breaker, distributed transactions, and any task requiring microservice design decisions or migration strategies.
How do I install microservices?
Run npx skills add AbsolutelySkilled/AbsolutelySkilled --skill microservices in your terminal. The skill will be immediately available in your AI coding agent.
What AI agents support microservices?
This skill works with claude-code, gemini-cli, openai-codex. Install it once and use it across any supported AI coding agent.
Maintainers
Generated from AbsolutelySkilled
SKILL.md
Microservices Architecture
Microservices is an architectural style that structures an application as a collection of small, independently deployable services, each owning its domain and data. Each service runs in its own process and communicates through lightweight mechanisms like HTTP/gRPC or async messaging. The style enables teams to develop, deploy, and scale services independently, reducing coupling and increasing resilience. It trades the simplicity of a monolith for the operational complexity of distributed systems - that trade-off must be made deliberately.
When to Use This Skill
Trigger on these scenarios:
- Decomposing a monolith into services (strangler fig, domain extraction)
- Designing inter-service communication (sync vs async, REST vs gRPC vs events)
- Implementing distributed transaction patterns (saga, two-phase commit alternatives)
- Applying CQRS or event sourcing to a service or domain
- Designing an API gateway layer (routing, auth, rate limiting, aggregation)
- Setting up a service mesh (Istio, Linkerd, Consul Connect)
- Implementing resilience patterns (circuit breaker, bulkhead, retry, timeout)
- Defining service boundaries using Domain-Driven Design (bounded contexts)
Do NOT trigger for:
- Simple CRUD apps or early-stage products with a single team - a monolith is the right choice
- Tasks that are purely about infrastructure provisioning without architectural decisions
Key Principles
- Single responsibility per service - Each service owns exactly one bounded context. If you need to join data across services in the database layer, your boundaries are wrong.
- Smart endpoints, dumb pipes - Business logic lives in services, not in the message broker or API gateway. Pipes carry data; they do not transform it.
- Design for failure - Every network call can fail. Services must handle partial failures gracefully using timeouts, retries with backoff, circuit breakers, and fallbacks.
- Decentralize data ownership - Each service owns its own database. No shared databases. Cross-service queries are done through APIs or events, never direct DB access.
- Automate everything - Microservices require CI/CD pipelines, automated testing, health checks, and observability from day one. Without automation, operational overhead becomes unmanageable.
Core Concepts
Service Boundaries
Define boundaries using Domain-Driven Design bounded contexts. A bounded context is a logical boundary within which a domain model is consistent. Map organizational structure (Conway's Law) to service boundaries. Services should be loosely coupled (change one without changing others) and highly cohesive (related behavior stays together).
Communication Patterns
| Style | Protocol | Use When |
|---|---|---|
| Synchronous | REST, gRPC | Immediate response needed, simple request-response |
| Asynchronous | Kafka, RabbitMQ, SQS | Decoupling, fan-out, event-driven workflows |
| Streaming | gRPC streams, SSE | Real-time data, large payloads, subscriptions |
Prefer async for cross-domain operations. Use sync only when the caller truly cannot proceed without the response.
Data Consistency
Distributed systems cannot guarantee both consistency and availability simultaneously (CAP theorem). Embrace eventual consistency for cross-service data. Use the saga pattern for distributed transactions. Never use two-phase commit across service boundaries - it creates tight coupling and is a single point of failure.
Service Discovery
Services find each other through a registry (Consul, Eureka) or via DNS with Kubernetes. Client-side discovery puts load-balancing logic in the client. Server-side discovery delegates to a load balancer. In Kubernetes, use DNS-based discovery with Services objects.
Observability
The three pillars: logs (structured JSON, correlation IDs), metrics (RED: Rate, Errors, Duration), traces (distributed tracing with OpenTelemetry). Every service must emit all three from day one. Correlation IDs must propagate across all service calls.
Common Tasks
Decompose a Monolith
Use the strangler fig pattern: incrementally extract functionality without a big-bang rewrite.
- Identify bounded contexts in the monolith using event storming or domain modeling
- Stand up an API gateway in front of the monolith
- Extract the least-coupled domain first as a new service
- Route traffic for that domain through the gateway to the new service
- Repeat domain by domain, shrinking the monolith over time
- Decommission the monolith when empty
Key rule: never split by technical layer (all controllers, all DAOs). Split by business capability.
Implement Saga Pattern
Use sagas to manage distributed transactions without two-phase commit. Two variants:
Choreography saga (event-driven, no central coordinator):
- Each service listens for domain events and emits its own events
- Compensating transactions roll back on failure
- Good for simple flows; hard to trace complex ones
Orchestration saga (central coordinator drives the flow):
- A saga orchestrator sends commands to each participant and tracks state
- On failure, the orchestrator issues compensating commands in reverse order
- Prefer for complex multi-step flows - easier to reason about and observe
Compensating transactions must be idempotent. Design them upfront, not as an afterthought.
Design API Gateway
The API gateway is the single entry point for external clients. Responsibilities:
- Routing - map external URLs to internal service endpoints
- Auth/AuthZ - validate JWTs or API keys before forwarding
- Rate limiting - protect services from abuse
- Request aggregation - combine multiple service calls into one response (BFF pattern)
- Protocol translation - REST externally, gRPC internally
Do NOT put business logic in the gateway. Keep it thin. Use the Backend for Frontend (BFF) pattern when different clients (mobile, web) need different response shapes.
Implement Circuit Breaker
The circuit breaker pattern prevents cascading failures when a downstream service is unhealthy.
States: Closed (requests flow normally) -> Open (fast-fail, no requests sent) -> Half-Open (probe with limited requests).
Implementation checklist:
- Set a failure threshold (e.g., 50% error rate over 10 requests)
- Set a timeout for the open state before transitioning to half-open
- Log all state transitions as events
- Expose circuit state in health endpoints
- Pair with a fallback (cached response, default value, or degraded mode)
Libraries: Resilience4j (Java), Polly (.NET), opossum (Node.js), circuitbreaker (Go).
Choose Communication Pattern
| Decision | Recommendation |
|---|---|
| Need immediate response | REST or gRPC (sync) |
| Decoupling producer from consumer | Async messaging (Kafka, SQS) |
| High-throughput, ordered events | Kafka |
| Simple task queuing | RabbitMQ or SQS |
| Internal service-to-service (low latency) | gRPC (contract-first, strongly typed) |
| Public-facing API | REST (broad tooling, human readable) |
| Fan-out to multiple consumers | Pub/sub (Kafka topics, SNS) |
Never mix sync and async in a way that hides latency - if you call an async system synchronously (poll or long-poll), make that explicit.
Implement CQRS
Command Query Responsibility Segregation separates read and write models.
- Write side: accepts commands, validates invariants, persists to write store, emits domain events
- Read side: subscribes to domain events, builds denormalized read models optimized for queries
Steps to implement:
- Separate command handlers from query handlers at the code level first (logical CQRS)
- Introduce separate read and write datastores when read/write performance profiles diverge
- Populate the read store by consuming domain events from the write side
- Accept that read models are eventually consistent with the write store
CQRS is often paired with event sourcing (storing events as the source of truth) but does not require it.
Design Service Mesh
A service mesh handles cross-cutting concerns (mTLS, retries, observability) at the infrastructure layer via sidecar proxies, removing them from application code.
Components:
- Data plane: sidecar proxies (Envoy) intercept all traffic
- Control plane: configures proxies (Istio Pilot, Linkerd control plane)
Capabilities to configure:
- mTLS between all services (zero-trust networking)
- Distributed tracing via header propagation
- Traffic shaping (canary deployments, A/B testing)
- Retry and timeout policies at the mesh level
Only adopt a service mesh when you have 10+ services and the cross-cutting concerns cannot be handled consistently at the application layer.
Anti-patterns / Common Mistakes
| Anti-pattern | Problem | Fix |
|---|---|---|
| Shared database | Tight coupling, eliminates independent deployability | Each service owns its own schema |
| Distributed monolith | Services are fine-grained but tightly coupled via sync chains | Redesign boundaries, introduce async communication |
| Chatty services | Too many small sync calls per request, high latency | Coarsen service boundaries or use async aggregation |
| Skipping observability | Cannot debug failures in distributed system | Instrument with logs, metrics, traces before going to production |
| Big-bang migration | Rewriting the entire monolith at once | Use strangler fig - migrate incrementally |
| No idempotency | Retries cause duplicate side effects | Design all endpoints and consumers to be idempotent |
Gotchas
Choreography sagas are deceptively hard to debug at scale - In a choreography saga, each service reacts to events independently. There is no central coordinator to query for "what step are we on?" When a saga fails mid-way, tracing which compensating transactions ran and which did not requires correlating events across multiple services' logs by correlation ID. Prefer orchestration sagas for flows with more than 3-4 participants, and invest in distributed tracing from day one.
The strangler fig pattern stalls without an API gateway - Teams try to route traffic to the new service by updating clients directly. This requires coordinated deployment of every client and the new service simultaneously, defeating the incremental migration goal. An API gateway (or reverse proxy) that owns routing is mandatory for strangler fig to work; the gateway lets you shift traffic without touching clients.
Event-driven eventual consistency surprises users when reads lag behind writes - A user submits a form, the command is processed and an event emitted, but when they immediately reload the page the read model hasn't updated yet. This is expected in CQRS with async projection but is not acceptable UX without mitigation. Use optimistic UI updates on the client side, or add a short read-your-own-writes guarantee for the creating user's session.
Circuit breakers need per-dependency instances, not a single global one - A single circuit breaker protecting all downstream calls means one slow service opens the breaker and blocks all outbound calls. Instantiate separate circuit breakers per downstream dependency so a failure in Service B does not degrade calls to Service C.
Shared library updates become de-facto distributed deployments - Putting business logic or domain types in a shared library that all services depend on means updating that library forces a coordinated upgrade across all services. This reintroduces the coupling microservices were meant to remove. Keep shared libraries limited to infrastructure concerns (logging, tracing, auth middleware) and keep domain logic strictly inside the owning service.
References
references/patterns.md- Detailed coverage of saga, CQRS, event sourcing, circuit breaker, bulkhead, sidecar, ambassador, strangler fig- Building Microservices - Sam Newman
- Microservices Patterns - Chris Richardson
- microservices.io - Pattern catalog with diagrams
- Martin Fowler - Microservices
- CAP Theorem
- Domain-Driven Design - Eric Evans
References
patterns.md
Microservice Patterns Reference
Detailed implementation guidance for core microservice patterns. Each pattern section covers intent, when to use it, how it works, and implementation notes.
Saga Pattern
Intent: Manage distributed transactions across multiple services without two-phase commit.
How it works: A saga is a sequence of local transactions. Each local transaction updates the service's own database and publishes an event or sends a command. If a step fails, compensating transactions execute in reverse order to undo the completed steps.
Choreography-based Saga
No central coordinator. Each service reacts to events and emits its own events.
OrderService --[OrderCreated]--> PaymentService
PaymentService --[PaymentProcessed]--> InventoryService
InventoryService --[StockReserved]--> ShippingService
On failure:
InventoryService --[StockReservationFailed]--> PaymentService (compensate: refund)
PaymentService --[PaymentRefunded]--> OrderService (compensate: cancel order)- Pros: No single point of failure, loose coupling
- Cons: Hard to trace across services, complex to understand the overall flow
Orchestration-based Saga
A saga orchestrator (dedicated service or state machine) sends commands and tracks progress.
SagaOrchestrator:
1. Send ReserveStock to InventoryService
2. On StockReserved: Send ProcessPayment to PaymentService
3. On PaymentProcessed: Send CreateShipment to ShippingService
4. On failure at any step: issue compensating commands in reverse- Pros: Explicit flow, easy to trace, clear failure handling
- Cons: Orchestrator can become a bottleneck; adds another service to maintain
Implementation rules:
- All compensating transactions must be idempotent
- Use a saga log / state machine to survive orchestrator crashes
- Publish events atomically with DB writes using the transactional outbox pattern
CQRS (Command Query Responsibility Segregation)
Intent: Separate the model used for writes (commands) from the model used for reads (queries).
How it works:
Client
|-- Command (write) --> Command Handler --> Write Store (normalized)
| |
| +--> Domain Event
| |
| Event Handler --> Read Store (denormalized)
|
+-- Query (read) --> Query Handler --> Read StoreLogical CQRS (same datastore, separated code)
Separate command and query handlers in code. Both read from the same database but use different models. Start here before introducing separate stores.
Physical CQRS (separate datastores)
- Write store: normalized relational DB, optimized for consistency
- Read store: denormalized (Elasticsearch, Redis, read-replica), optimized for query patterns
- Sync via domain events (eventually consistent)
When to use: High read-to-write ratio, complex query requirements that differ from write requirements, need to scale reads independently.
Pitfalls:
- Read models are eventually consistent - design UX to handle this
- Increased operational complexity (two stores to maintain)
- Do not apply CQRS everywhere - only where there is a real read/write asymmetry
Event Sourcing
Intent: Store the state of a domain object as a sequence of events rather than current state.
How it works:
Traditional: DB row = {orderId: 1, status: "shipped", total: 100}
Event Sourced: event store = [
{type: "OrderCreated", orderId: 1, total: 100},
{type: "PaymentProcessed", orderId: 1, amount: 100},
{type: "OrderShipped", orderId: 1, trackingId: "XYZ"}
]
Current state = replay of all eventsBenefits:
- Full audit log of every state change
- Ability to rebuild any past state
- Natural fit for CQRS (events populate read models)
- Event stream is the integration contract
Drawbacks:
- Schema evolution of events is hard - cannot alter past events
- Rebuilding state from a long history is slow (use snapshots)
- Eventual consistency by default
- High cognitive overhead for developers unfamiliar with the pattern
Snapshots: Periodically capture current state as a snapshot. On replay, load the last snapshot then apply only subsequent events.
Circuit Breaker
Intent: Prevent cascading failures by stopping requests to a failing downstream service.
State Machine
[CLOSED] ---(failure threshold exceeded)---> [OPEN]
[OPEN] ---(timeout elapsed)-------------> [HALF-OPEN]
[HALF-OPEN] ---(probe succeeds)-----------> [CLOSED]
[HALF-OPEN] ---(probe fails)--------------> [OPEN]Configuration parameters
| Parameter | Description | Typical value |
|---|---|---|
| Failure threshold | % of failures to trip to OPEN | 50% |
| Minimum requests | Minimum calls before evaluating | 10 |
| Open timeout | How long to stay OPEN before probing | 30-60s |
| Slow call threshold | Duration considered a slow call | 1-2s |
Fallback strategies (in order of preference)
- Return cached / stale data
- Return a degraded response (partial data)
- Return a default / empty response
- Fail fast with a meaningful error (last resort)
Libraries
| Language | Library |
|---|---|
| Java | Resilience4j, Hystrix (deprecated) |
| .NET | Polly |
| Node.js | opossum, cockatiel |
| Go | gobreaker, sony/gobreaker |
| Python | pybreaker |
Bulkhead
Intent: Isolate failures by partitioning resources so that a failure in one partition does not exhaust resources for others.
Analogy: Ship bulkheads - compartments prevent the whole ship from sinking if one section floods.
Thread pool bulkhead
Assign separate thread pools to different downstream calls. If the payment service is slow and exhausts its pool, the user service pool is unaffected.
[HTTP Request Pool]
├── [Payment Service Pool: 10 threads]
├── [Inventory Service Pool: 10 threads]
└── [User Service Pool: 10 threads]Semaphore bulkhead
Limit concurrent calls to a downstream service using a semaphore rather than a separate thread pool.
When to use: When you have many downstream dependencies and want to prevent any single slow dependency from saturating your application's thread pool or connection pool.
Combine with: Circuit breaker (bulkhead limits concurrent calls; circuit breaker stops calls entirely when the service is unhealthy).
Sidecar Pattern
Intent: Offload cross-cutting concerns (logging, tracing, mTLS, config) into a separate process (the sidecar) that runs alongside the main service container.
How it works: The sidecar container shares the same network namespace and lifecycle as the primary container (same Pod in Kubernetes). All inbound and outbound traffic is intercepted by the sidecar proxy.
[Pod]
├── [App Container] <--> localhost <--> [Sidecar Proxy (Envoy)]
└── [Sidecar handles: mTLS, retries, tracing, metrics]Common sidecar responsibilities:
- mTLS termination and certificate rotation
- Distributed tracing header injection
- Metrics collection (Prometheus scraping)
- Log shipping
- Config/secret fetching (Vault agent injector)
Used by: Istio, Linkerd, Dapr, AWS App Mesh
Ambassador Pattern
Intent: Create a helper service that sends network requests on behalf of a service, handling cross-cutting concerns like retry, timeout, and circuit breaking without changing the application.
Difference from sidecar: The ambassador pattern is a conceptual pattern; a sidecar is the deployment mechanism. An ambassador proxy is a sidecar that specifically handles outbound network traffic.
Use cases:
- Legacy services that cannot be modified but need circuit breaking added
- Standardizing retry and timeout policies across polyglot services
- Monitoring outbound calls without modifying application code
[Legacy Service] --> [Ambassador Proxy] --> [Downstream Service]
(handles retry, CB, mTLS)Strangler Fig Pattern
Intent: Incrementally migrate a monolith to microservices by routing traffic to new services while the monolith shrinks.
Named after: The strangler fig tree, which grows around a host tree and eventually replaces it.
Migration steps
- Facade first: Place an API gateway or reverse proxy in front of the monolith. No behavior change yet.
- Identify a domain: Pick the least-coupled, most well-defined bounded context to extract first.
- Build the new service: Implement the domain logic in the new service with its own data store.
- Migrate data: Sync data from the monolith to the new service's store (dual-write or backfill).
- Route traffic: Switch the gateway to route that domain's requests to the new service.
- Remove from monolith: Delete the migrated code from the monolith.
- Repeat: Iterate for each domain.
Data migration approaches
| Approach | Description | Risk |
|---|---|---|
| Dual-write | Write to both old and new store during transition | Low - easy to roll back |
| Backfill + cutover | Backfill historical data, then cut over | Medium - requires data freeze or reconciliation |
| Event replay | Replay events to populate new store | Low if events are available |
Do not:
- Extract many services at once
- Cut over before the new service has proven reliability in production
- Neglect to remove the extracted code from the monolith (creates a distributed monolith)
Transactional Outbox Pattern
Intent: Guarantee that a database write and a message publish happen atomically, preventing message loss on service crash.
Problem: Writing to DB and publishing to a message broker are two separate operations. A crash between them leaves the system in an inconsistent state.
Solution:
Service:
BEGIN TRANSACTION
INSERT INTO orders (...)
INSERT INTO outbox (event_type, payload, published=false)
COMMIT
Outbox Poller (separate process):
SELECT * FROM outbox WHERE published = false
FOR EACH event:
publish to message broker
UPDATE outbox SET published = true WHERE id = ?The outbox table lives in the same database as the domain data, so the write is a single local transaction. The poller handles publishing asynchronously.
Variants:
- Polling publisher: Simple poller queries the outbox table
- Transaction log tailing (CDC): Debezium or similar tools tail the database WAL and publish changes - lower latency, no polling load on DB
API Gateway Pattern
Intent: Provide a single entry point for all client requests, handling cross-cutting concerns and routing to appropriate backend services.
Responsibilities
| Responsibility | Notes |
|---|---|
| Routing | Map URL paths to backend services |
| Authentication | Validate tokens before forwarding |
| Rate limiting | Per-client or per-endpoint throttling |
| SSL termination | Terminate HTTPS at the gateway |
| Request/response transformation | Header manipulation, protocol translation |
| Aggregation | Compose multiple service responses (BFF) |
| Caching | Cache frequently requested, slowly-changing responses |
Backend for Frontend (BFF)
Create separate API gateway instances (or route configurations) for different client types:
Mobile App --> [Mobile BFF] --> Service A, Service B
Web App --> [Web BFF] --> Service A, Service C
Partner API --> [Partner GW] --> Service D (subset of API)BFF enables each client to get exactly the data it needs without over-fetching or under-fetching, and allows mobile-specific optimizations (payload compression, reduced fields).
Tools: Kong, AWS API Gateway, nginx, Envoy, Traefik, Azure API Management
Service Mesh
Intent: Handle service-to-service communication concerns (observability, security, resilience) at the infrastructure layer, removing them from application code.
Architecture
[Control Plane] --(config)--> [Data Plane: Envoy sidecars on every pod]
(Istio Pilot /
Linkerd control plane)Capabilities
| Capability | Description |
|---|---|
| mTLS | Automatic certificate rotation, zero-trust networking |
| Traffic management | Canary releases, A/B testing, traffic mirroring |
| Observability | Automatic distributed traces, metrics, access logs |
| Retries & timeouts | Configured at mesh level, not in application code |
| Circuit breaking | Outlier detection at the proxy layer |
When to adopt
- You have 10+ services and cross-cutting concerns are inconsistently implemented
- You need zero-trust networking (mTLS between all services)
- You want canary deployments and traffic splitting without application changes
Do not adopt a service mesh for fewer than 5-10 services - the operational overhead is not justified.
Tools: Istio, Linkerd, Consul Connect, AWS App Mesh, Kuma
Frequently Asked Questions
What is microservices?
Use this skill when designing microservice architectures, decomposing monoliths, implementing inter-service communication, or solving distributed data challenges. Triggers on service decomposition, saga pattern, CQRS, event sourcing, API gateway, service mesh, circuit breaker, distributed transactions, and any task requiring microservice design decisions or migration strategies.
How do I install microservices?
Run npx skills add AbsolutelySkilled/AbsolutelySkilled --skill microservices in your terminal. The skill will be immediately available in your AI coding agent.
What AI agents support microservices?
microservices works with claude-code, gemini-cli, openai-codex. Install it once and use it across any supported AI coding agent.