APIs Don’t Follow Domains. They Follow Capabilities.
Why Domain Driven Design alone leads to leaky APIs and how capability thinking creates stable and evolvable interfaces
There is a persistent assumption in modern architecture discussions that once the domain is properly understood, the APIs will naturally fall into place. Domain-Driven Design is often treated as the upstream activity that implicitly defines service boundaries and, by extension, API contracts. It is an appealing idea because it promises conceptual purity. If the model is correct, everything else should align.
In practice, this assumption rarely holds. Instead of clarity, it produces APIs that mirror internal structures, expose domain complexity, and are difficult to evolve. The problem is not Domain-Driven Design itself, but the expectation that it should directly inform how systems are consumed.
Separating Concerns: Domain, Capability, and API
In a previous article
the argument was made that APIs are not the system. They are an expression of what a system does. This distinction is critical, because it shifts the focus away from implementation and toward responsibility. If APIs are expressions, then the question becomes what exactly they are expressing.
To answer that, it helps to separate three distinct concerns that are often conflated. Domain-Driven Design is concerned with meaning. It helps structure the understanding of a complex business domain, define boundaries of consistency, and align language between stakeholders and engineers. Capability thinking is concerned with responsibility. It defines what a system actually provides in terms of outcomes. API Design First is concerned with interaction. It defines how those outcomes are exposed and consumed under conditions of independent evolution.
These concerns are related, but they are not interchangeable. Problems begin when they are collapsed into a single layer, usually by assuming that domain boundaries should directly translate into APIs.
The Real Problem: Model Leakage and API Sprawl
The typical chain of reasoning looks straightforward. A bounded context is identified. That context becomes a service. The service exposes an API. The domain model becomes the API schema. Aggregates turn into resources, entities into representations, and domain language becomes the contract. The result is an API surface that reflects how the system is built rather than what it offers.
This is where API sprawl begins. It is not primarily a scaling problem or a matter of too many services. It is a modeling leakage problem. Internal structure is exposed as external contract. Consumers are forced to understand domain concepts that were never meant for them. Workflows are fragmented across multiple endpoints. Orchestration shifts to the consumer side. What looks like a well-structured domain internally turns into a confusing interaction model externally.
The root cause is not Domain-Driven Design, but the absence of an intermediate abstraction. Capability thinking fills that gap. A capability describes a cohesive unit of business functionality that delivers a meaningful outcome, independent of how it is implemented. It is neither as fluid as a domain model nor as rigid as an API contract. It provides a stable anchor between the two.
Domains evolve as understanding deepens. Concepts are refined, boundaries are adjusted, and models change over time. APIs, on the other hand, must remain stable because they are consumed across independent lifecycles. Capabilities sit between these forces. They are stable enough to serve as a foundation for APIs, yet meaningful enough to remain grounded in the business.
Designing for Outcomes: Capabilities as the Anchor
When APIs are designed around capabilities rather than domains, the interaction model shifts. Instead of exposing internal structures, the system exposes outcomes. Instead of requiring consumers to navigate aggregates and entities, it provides entry points aligned with real use cases. The API surface becomes smaller, more coherent, and easier to evolve.
This also clarifies a common misconception about internal and external APIs. The distinction is often framed in terms of network boundaries or visibility, but that is not what matters. The relevant factor is whether components evolve together or independently. The moment independent evolution is introduced, explicit contracts become necessary. Capability boundaries often align with these points of independence, which is why APIs tend to emerge naturally around them regardless of whether they are labeled internal or external.

Revisiting Domain-Driven Design in this context leads to a more precise understanding of its role. DDD is essential for making sense of the system. It defines the language, the invariants, and the structure of the domain. It should inform how the system is built internally. What it should not do is dictate how the system is exposed. Treating domain models as APIs exports internal complexity and couples consumers to concepts that are still evolving.
A more effective approach is to let each discipline operate on its intended level. Domain-Driven Design explains the system. Capability thinking defines what the system is responsible for. API Design First determines how that responsibility is made accessible. The boundaries between these layers are not weaknesses. They are where architectural decisions actually take shape.
The practical implication is straightforward. Start by identifying capabilities rather than endpoints. Focus on the outcomes the system must provide. Use domain modeling to ensure those capabilities are implemented correctly. Then design APIs that make those capabilities usable and stable over time. Accept that translation between these layers is not overhead but necessary work to prevent leakage and coupling.
The shift from domains to capabilities is not about replacing one paradigm with another. It is about recognizing that different problems require different abstractions. Domains capture meaning. Capabilities capture intent. APIs capture interaction. When these are aligned deliberately rather than conflated, systems become easier to understand, easier to use, and easier to evolve.
The conclusion from the earlier article still holds. APIs are not the system. They are an expression of what the system does. The extension of that idea is equally important. What they should express is not the domain itself, but the capabilities derived from it.

