Bounded Contexts

A bounded context defines the scope in which a domain model and its terminology have consistent meanings. Separate contexts can model the same real-world thing differently and cooperate through explicit integrations.

In Domain-Driven Design, a bounded context is the explicit scope in which a domain model and its terms have consistent meanings. The same word can legitimately refer to different concepts in different contexts: for example, a “product” in a catalog may have a name and description, while an inventory product may be identified by a stock-keeping unit and quantity.

Within a context, the model should be coherent: rules, names, and behavior align with the problem that context handles. Teams use a ubiquitous language there, expressed in conversations, code, and documentation. If a term becomes ambiguous across different parts of a system, that can be a sign that they belong to distinct contexts rather than one universal model.

Contexts need explicit ways to cooperate. They may exchange messages or call APIs, with translation between their models at the boundary. A context map describes relationships between contexts and can document integration choices, ownership, and dependencies. Translation may be handled by an adapter or an anti-corruption layer that keeps an external model from distorting the local one.

A bounded context is a domain-design boundary, not automatically a separate process, team, database, or microservice. Those boundaries may align when useful, but the decision depends on organizational and operational needs. Start by clarifying model ownership and interactions, then choose an implementation and deployment structure.

Key points

Interview questions

What is a bounded context in Domain-Driven Design?

A bounded context defines where a particular domain model and its language are valid and consistent. Inside it, terms, rules, and code should describe the same concepts. Different contexts can use the same word differently without forcing one model to satisfy both meanings. They integrate through explicit boundaries and, when necessary, translation.

How would you handle a concept such as Customer that differs between sales and billing?

The word “customer” may mean a prospective buyer in a sales context, but a billing context may care about an account with payment terms and invoices. Each context can model the fields and rules it needs rather than sharing one oversized Customer object. When data crosses the boundary, an integration contract and translation define which information is exchanged. This keeps local models meaningful while making the relationship explicit.

Does every bounded context need to be a microservice?

A bounded context is a domain boundary, whereas a microservice is an independently deployable software unit. They can align, but that is not required: a monolith can contain several contexts, and a service can contain more than one context. Splitting contexts into services adds operational and network costs, so it should be driven by needs such as independent ownership, scaling, or release cadence. I would establish model boundaries first and choose deployment boundaries deliberately.

How would you discover bounded contexts in an unfamiliar domain?

I would identify the capabilities involved, the language used by the people doing the work, and where the rules or meanings diverge. Then I would look for ownership boundaries, existing integration points, and changes that frequently cause coordination. Candidate contexts should have coherent models and explicit relationships, not just separate tables or teams. I would validate the boundaries with domain experts and revise them as understanding improves.

What is an anti-corruption layer, and how does it relate to bounded contexts?

An anti-corruption layer is a translation mechanism that protects a context's model from an external system's concepts and constraints. It can map external messages or API responses into local types and translate local requests into the external contract. This is particularly useful when integrating with a legacy system or a context whose model should not dictate local design. It is an integration pattern, not a required component of every bounded context.