Domain, Subdomain, Bounded Context: The Three-Level Split
What This Concept Is
Strategic DDD starts by splitting one confused word ("the system") into three levels:
- Business domain -- what the company does for its customers. One sentence describing the service it sells.
- Subdomain -- a fine-grained area of business activity the company has to operate in to deliver on the business domain.
- Bounded context -- a software boundary inside which one ubiquitous language applies consistently.
The three levels are not synonyms and not a hierarchy you can collapse. Subdomains belong to the problem space (what the business has to do). Bounded contexts belong to the solution space (how software carves the work). The two do not have to map one-to-one, and pretending they do is the most expensive mistake in this module.
Why It Matters Here
If you cannot separate these three levels, every later decision gets contaminated:
- classifying a subdomain becomes impossible because "the whole system" is the subdomain
- drawing a context map becomes impossible because every box is both a subdomain and a context
- choosing between CQRS, event sourcing, and plain CRUD becomes impossible because the classification that guides those choices does not exist
- microservice boundaries drift toward "one service per table" instead of "one service per context"
Every primary concept in this module uses this split as its common vocabulary.
Concrete Example
Case: Parcel Shipping Co.
- Business domain (one sentence): "We sell shipping labels and deliver parcels on behalf of small and medium retailers."
- Subdomains (problem space, not yet software):
rating & pricing-- computing the price of a shipment based on weight, dimensions, zone, carrier, and customer contractlabel generation-- producing carrier-compliant PDF and ZPL labels with barcodesparcel tracking-- ingesting carrier scans and emitting a unified status streamcarrier integration-- mediating with 12 carrier APIs that each have their own quirksbilling & invoicing-- aggregating shipments into monthly invoices, handling disputescustomer support-- case management for a customer-service teamidentity & access-- authenticating retailers and their staffanalytics-- internal BI and customer-facing dashboards
- Bounded contexts (solution space, drawn after subdomains):
Pricing Contextcovers therating & pricingsubdomainShipping Contextcoverslabel generationand part ofparcel trackingTracking Contextcovers the rest ofparcel trackingplus the public tracking-page read modelCarrier Gateway Contextcoverscarrier integrationand nothing elseBilling Contextcoversbilling & invoicingSupport Contextcoverscustomer support- an external
identity providercoversidentity & access(generic, bought in) - an external warehouse covers
analytics
Notice the asymmetry: parcel tracking (one subdomain) is split across two bounded contexts. That is allowed and common. The subdomain is a business classification; the context is a software decision driven by language, team, and consistency needs.
Mermaid view of the split:
Common Confusion / Misconception
"Bounded context == microservice." A bounded context is a model boundary, not a deployment boundary. A modular monolith can contain multiple bounded contexts in one deployable. What the bounded context promises is one consistent language inside it; deployment topology is a separate decision.
"Domain and subdomain are just 'system' and 'module' with fancier names." No. Domain is about the company's business, not about software. You could write the subdomain list for a company that has no software at all (and real DDD analysis often does exactly that before touching code).
"We have 40 subdomains." Maybe you have. More likely you have confused subdomains with features. A subdomain is an area of business activity that could plausibly be run by a team and whose absence would hurt the business. "Password reset" is a feature inside the identity subdomain, not its own subdomain.
"We need one bounded context per subdomain." Sometimes; often not. Two related subdomains can share a context if their languages are compatible. One subdomain can split across two contexts for scaling, team, or lifecycle reasons. What must not happen: two contexts sharing the same model of the same subdomain simultaneously. That collapses the language boundary.
How To Use It
When you enter a new domain:
- Write the business domain in one sentence. Resist "we are a technology platform for X-as-a-service."
- List the subdomains the business has to operate in. Aim for 5-12. If you have three, you undercount; if you have 30, you are listing features.
- For each subdomain, ask: could another company buy this off the shelf? Does it differentiate us? How complex is its business logic?
- Then (not before) sketch bounded contexts in the solution space. Group subdomains if their languages can stay consistent together; split a subdomain across two contexts only with a stated reason.
- Draw a simple two-column view (subdomain list -> bounded context list) and keep it on a wiki page. It is the strategic backbone of everything else.
Check Yourself
- In your own product, what is one subdomain that is clearly not a bounded context (it spans two) and one bounded context that is clearly not a subdomain (it groups two)?
- Why is it harmful to promote "bounded context" into the org-chart synonym for "team"?
- A colleague says "we have a microservice for shipping, so shipping is our bounded context." What is the flaw, and what question do you ask to verify?
Mini Drill or Application
Pick one of:
- Conference Ticketing -- a SaaS that sells, issues, and validates tickets for technical conferences.
- Online bookstore with self-published authors.
- Food-delivery platform with restaurant integrations.
For your chosen case, produce:
- the business domain in one sentence
- 6-10 subdomains
- 4-8 bounded contexts
- at least one example where a subdomain splits across two contexts, with a stated reason
- at least one example where one context covers two subdomains, with a stated reason
Keep it to one page. If it spills over, you are listing features.