skip to content

The usual advice is 'one bounded context maps to one service.' Under what circumstances is it reasonable to run several bounded contexts inside a single service, or conversely to split one bounded context across several services, and what risk does each deviation carry?

level: seniorimportance: should knowfreq 50%

answer

  1. default not a law
  2. merge small stable contexts = ok
  3. split only along real sub-seams (aggregates)
  4. arbitrary split = distributed monolith

basics

~20 s

Sometimes it's fine to put two related but minor business areas in one service if they're small and rarely change, to avoid running lots of tiny services. But splitting one business area's logic across several services usually causes trouble, because it breaks up something that should stay together.

solid answer

~50 s

'One context, one service' is a default, not a law. Running multiple small, low-traffic, rarely-changing bounded contexts inside one service is reasonable early on or for genuinely minor contexts, trading some independent deployability for lower operational overhead — as long as module boundaries stay clean internally so they can be split out later if needed. The reverse — splitting one bounded context across multiple services — is riskier and usually a mistake unless done deliberately for a very large context, where you still keep each sub-piece's aggregates whole and define an internal context map between the pieces; done carelessly, it just produces two services fighting over one shared, ambiguous model, i.e., a distributed monolith. The core risk of merging contexts is coupling two independent evolution rates into one deployment unit; the core risk of splitting one context is silently recreating cross-service transactions and shared-model ambiguity that DDD boundaries exist to avoid.

go deeper

for a junior

Should understand that 'one context per service' is a common default, without necessarily being able to argue for exceptions.

for a middle

Should be able to give a simple example of when bundling small contexts is acceptable and recognize that splitting a context poorly causes coupling problems.

for a senior

Should be able to design an internal module boundary that keeps a multi-context service extractable later, and correctly diagnose whether a 'split' proposal follows real sub-context seams or arbitrary technical ones.

for a principal

Should be able to set org-wide policy on when merging/splitting deviations are acceptable, weigh operational cost against architectural purity across dozens of services, and lead a large-context decomposition (e.g. splitting an outgrown context) without breaking existing consumers.

## A default, not a law *One bounded context per service* is the standard heuristic for aligning DDD modeling with microservice decomposition, but it's a starting default tuned for the common case, not an inviolable law — real systems have legitimate reasons to deviate in both directions, and the risk profile of each deviation is different. ## Several contexts inside one service Running several bounded contexts inside one physical service is the **more defensible deviation**. The mechanism here is that a *service* in the deployment sense (one deployable unit, one runtime) doesn't have to equal exactly one bounded context in the modeling sense — you can build a service with clean internal module boundaries — one module per bounded context, all still deploying together — where each module has: - its own package/namespace; - its own internal model; - and (ideally) its own logical data partition, even inside a shared physical database. Teams do this deliberately for contexts that are small, low-traffic, and unlikely to need independent scaling or independent release cadence — think a Notifications-Preferences context and an Audit-Log context bundled into one small *Platform Utilities* service rather than each getting its own repo, pipeline, and on-call rotation. The trade-off is **operational efficiency** (fewer services to deploy, monitor, and staff) against **reduced independent deployability** — if one of those bundled contexts later needs to scale or release independently, you have to do the (nontrivial) work of extracting it into its own service. This deviation is common and often sensible early in a system's life, or for a genuinely minor context that will probably never need its own lifecycle, with the internal module boundaries kept clean specifically so a later extraction is a refactor, not a rewrite. ## One context across several services Splitting a single bounded context across multiple services is the riskier and much less common deviation, and it's usually a mistake when done accidentally — for instance when a context turns out, after the fact, to have been drawn too large during modeling and gets bisected along arbitrary lines (often database tables) rather than a real internal seam. The failure mode is exactly the one covered by the aggregate-boundary rule: if you cut through the middle of what was really one coherent model, you end up with two services that both think they own part of the same concept, forcing distributed transactions or constant renegotiation of a shared, ambiguous model — effectively rebuilding the coordination problem bounded contexts exist to eliminate, just now with network calls in between. ## The legitimate version of a split There is, however, a legitimate version of splitting a context: when a bounded context is genuinely very large — big enough that a single team or service can't reasonably own and scale it — the correct move isn't to bisect it randomly but to look inside it for smaller, independently-consistent sub-boundaries (often along aggregate lines) and promote those to their own services, each still respecting the aggregate-wholeness rule, connected by an internal context map (often Open Host Service/Published Language between the pieces, since they're really the same team's domain expressed as several cooperating services). This is less *splitting a bounded context* and more *discovering that what looked like one large context was actually several smaller ones sharing a team and a domain area* — the distinction matters because the sub-services still each own a complete, coherent piece of the model, rather than a partial, dependent slice of one. ## Where it shows up A concrete illustration: - **A split along a domain seam.** An e-commerce Catalog context that starts as one service can grow large enough (product data, search indexing, pricing rules, inventory-availability display) that a team splits it into a Product-Info service, a Search/Indexing service, and a Pricing service — each still a complete bounded context with its own aggregates and model, connected by domain events (`ProductUpdated` triggering a reindex) rather than shared tables. - **A split along a technical axis, for contrast.** A team that instead splits Catalog into a *Reads* service and a *Writes* service purely along a CQRS-flavored technical axis without a domain justification — that split usually reintroduces tight coupling (the read service needs to understand every field the write service produces) without gaining a genuine domain seam. ## Practical guidance The practical guidance for a working engineer is to: 1. Treat *one context, one service* as the safe default. 2. Deliberately choose to merge only for small/stable contexts where the operational savings clearly outweigh lost independence. 3. Treat any proposal to split a context as a signal to first ask whether the *context* was actually mis-scoped to begin with — because a clean split along real aggregate/sub-context lines is a legitimate architecture decision, while an ad hoc split along storage or team convenience is the single most common way teams recreate a distributed monolith while believing they've done proper microservice decomposition.

  • What internal design discipline lets a team later extract one bounded context out of a multi-context service without a rewrite?
    Keeping each bounded context in its own module/package with an explicit internal API between modules — never letting one context's code directly reach into another's internal classes or tables — so the seam already exists in code even before it exists in deployment. If the internal boundary has been kept clean, extraction is largely a matter of standing up a new deployable, moving the module's code and its slice of the database, and replacing the in-process call with a network call.
  • A team wants to split its large 'Fulfillment' bounded context into two services purely because the database has gotten too big to fit on one instance. Why is this reasoning risky compared to splitting along aggregate lines?
    Splitting by raw storage size ignores where the domain's actual consistency boundaries are, so the split is likely to bisect an aggregate or force two services to jointly enforce one invariant, recreating the distributed-transaction problem service boundaries are meant to avoid. The safer approach is to first identify which aggregates or sub-contexts within Fulfillment are naturally independent (e.g. Shipping vs. Returns) and split along that seam, even if it doesn't perfectly balance database size on both sides.
  • Under what condition would deliberately merging two clearly-distinct bounded contexts into one service still be a bad idea, even if both are individually small?
    If the two contexts have very different scaling profiles, release cadences, or reliability requirements — e.g. one is a rarely-touched Reporting context and the other is a latency-critical Checkout-adjacent context — bundling them means a deploy or an incident in the low-stakes context can take down or delay releases for the high-stakes one. Small size alone doesn't justify merging; the deviation only pays off when both contexts also share similar operational needs.

Like a small business housing both its accounting and HR functions in one back office because each is too small to justify its own department — fine as long as the filing cabinets (models) stay separate inside that office. Compare that to physically moving half of the accounting ledger to a different building: unless you cleanly divide by which accounts each building fully owns, you've just made bookkeeping harder for no real gain.

saying these in an interview costs you the question

  • Treats 'one context, one service' as a rule with zero exceptions
  • Can't name a legitimate reason to bundle multiple small contexts into one service
  • Recommends splitting a context along database size/table count without checking aggregate boundaries
  • Doesn't recognize a bad split as a source of distributed-monolith symptoms
  • Assumes merging contexts has no downside as long as the service still 'works'

context