What is Microservices Granularity
Article date
05 12 2026
Article Author
Alexander Krstich
Reading Time
5 minutes
What is Microservices Granularity: How to Choose the Right Service Size and Not Drown in Complexity
On the agenda: a practical breakdown of microservices granularity — DDD boundaries, synchronous and asynchronous calls, sagas, outbox, SLOs, and metrics that help choose the right service size.
On the agenda: a practical breakdown of microservices granularity — DDD boundaries, synchronous and asynchronous calls, sagas, outbox, SLOs, and metrics that help choose the right service size.
1. Why the Question "How Small Should a Service Be?" Is More Important Than It Seems
In the microservices world, there is a temptation to simplify the rule to a single phrase: "the smaller the service, the better." It sounds impressive, but in a production system, this usually works only until the first incident. A service that is too large quickly turns into a mini-monolith, while services that are too small start to create network noise with retries, timeouts, and cascading failures.
Granularity is not about repository size or the number of containers in a cluster. It's about correct responsibility boundaries: where one business operation ends and another begins, where eventual consistency is acceptable, and where strict transactionality is required. At this stage, architecture either helps ship features or turns into an expensive distributed labyrinth.
Looking at it pragmatically, granularity directly impacts lead time for changes, MTTR, operational costs, and the team's cognitive load. The irony is that "micro" without engineering discipline easily becomes a "macro problem." Therefore, the main question is not "how small a service," but "how independent and manageable a service."
Granularity is not about repository size or the number of containers in a cluster. It's about correct responsibility boundaries: where one business operation ends and another begins, where eventual consistency is acceptable, and where strict transactionality is required. At this stage, architecture either helps ship features or turns into an expensive distributed labyrinth.
Looking at it pragmatically, granularity directly impacts lead time for changes, MTTR, operational costs, and the team's cognitive load. The irony is that "micro" without engineering discipline easily becomes a "macro problem." Therefore, the main question is not "how small a service," but "how independent and manageable a service."
2. What Granularity Means at the Engineering Level
Microservices granularity is choosing a level of decomposition where a service remains cohesive, autonomous in terms of data, and independently developable. A good boundary usually aligns with a bounded context from DDD: inside the service, there is a unified domain model and a ubiquitous language; outside, there is an explicit API or event contract.
Technically, this is very easy to verify. If a service owns its data schema (database-per-service), publishes a versioned contract (/v1, schema evolution for events), and can be deployed without a synchronous release of its neighbors — granularity is close to working. If every release requires "coordinating with three teams and five tables," the boundaries are poorly chosen.
Another important marker is the interaction profile. Synchronous calls via HTTP/gRPC are good for short requests with strict SLAs, but for long-running business processes, it's better to transition to an event-driven model via a broker (Kafka/RabbitMQ) and saga orchestration/choreography. This reduces coupling and helps survive partial failures without global locks.
Technically, this is very easy to verify. If a service owns its data schema (database-per-service), publishes a versioned contract (/v1, schema evolution for events), and can be deployed without a synchronous release of its neighbors — granularity is close to working. If every release requires "coordinating with three teams and five tables," the boundaries are poorly chosen.
Another important marker is the interaction profile. Synchronous calls via HTTP/gRPC are good for short requests with strict SLAs, but for long-running business processes, it's better to transition to an event-driven model via a broker (Kafka/RabbitMQ) and saga orchestration/choreography. This reduces coupling and helps survive partial failures without global locks.
3. How to Choose Boundaries: A Practical Tech Lead's Scheme
It's best to start with a business capability map and change-frequency analysis. If two modules almost always change together, they were split too early. If one requires independent scaling (e.g., search or recommendation) and the other is stable, separation is justified both economically and technically.
Next comes verification of transactions and consistency. If a scenario requires atomicity within a single domain operation, don't forcibly "cut" it into multiple services without compensations. In a distributed architecture, ACID between services is replaced by patterns: saga for business transactions, outbox/inbox for reliable delivery, and idempotency keys for safe retries.
After this, boundaries are validated by observability. Each service should have SLIs/SLOs: latency (p95/p99), error rate, saturation, throughput. If after decomposition p99 latency grows, along with the number of cross-service incidents and time to diagnosis, you've gained "diagram beauty" but lost in operability. Good granularity is one that improves real metrics, not just the diagram in Miro.
Next comes verification of transactions and consistency. If a scenario requires atomicity within a single domain operation, don't forcibly "cut" it into multiple services without compensations. In a distributed architecture, ACID between services is replaced by patterns: saga for business transactions, outbox/inbox for reliable delivery, and idempotency keys for safe retries.
After this, boundaries are validated by observability. Each service should have SLIs/SLOs: latency (p95/p99), error rate, saturation, throughput. If after decomposition p99 latency grows, along with the number of cross-service incidents and time to diagnosis, you've gained "diagram beauty" but lost in operability. Good granularity is one that improves real metrics, not just the diagram in Miro.
4. Typical Mistakes and How Not to Build a "Distributed Monolith"
The most common mistake is splitting by technical layers (user-controller-service-repo as separate services) rather than by business capabilities. The result is hundreds of network calls per single user scenario, fragile dependencies, and complex tracing. This is a distributed monolith — just with a more expensive production environment.
The second mistake is lack of contract discipline. Without a schema registry, event versioning, and backward compatibility, any release starts breaking neighbors. Add the absence of a correlation ID, and an incident turns into a quest: "who broke the chain?" Technical maturity here is more important than the "trendiness" of the architecture.
The third mistake is ignoring the platform foundation: service mesh, centralized logs, tracing (OpenTelemetry), rate limiting, circuit breakers, retries, and retry budgets. Without these mechanisms, even properly sliced services will be unstable under load. Microservices are always not just code, but also an operational platform.
The second mistake is lack of contract discipline. Without a schema registry, event versioning, and backward compatibility, any release starts breaking neighbors. Add the absence of a correlation ID, and an incident turns into a quest: "who broke the chain?" Technical maturity here is more important than the "trendiness" of the architecture.
The third mistake is ignoring the platform foundation: service mesh, centralized logs, tracing (OpenTelemetry), rate limiting, circuit breakers, retries, and retry budgets. Without these mechanisms, even properly sliced services will be unstable under load. Microservices are always not just code, but also an operational platform.
Engineering Conclusion
Granularity is a managerial and technical balance: domain boundaries, release independence, data autonomy, and control over interaction complexity. There is no universal "ideal service size" — there is a measurable effect from the chosen decomposition.
If in doubt, choose an evolutionary path: a modular monolith or larger services at the start, then split based on actual bottlenecks — load, SLAs, speed of changes, and team organizational boundaries. This approach reduces the cost of mistakes and keeps the architecture alive.
And yes, the most sober criterion is always the same: after the next "architecture improvement," has the team become faster and more reliable in their work — or have there simply become more diagrams? If the latter, granularity needs to be revisited.
If in doubt, choose an evolutionary path: a modular monolith or larger services at the start, then split based on actual bottlenecks — load, SLAs, speed of changes, and team organizational boundaries. This approach reduces the cost of mistakes and keeps the architecture alive.
And yes, the most sober criterion is always the same: after the next "architecture improvement," has the team become faster and more reliable in their work — or have there simply become more diagrams? If the latter, granularity needs to be revisited.