Skip to content

Concept

Bounded Context

Same word, different meaning behind different walls — group events, stay independent, map to services.

After event storming gives you sequenced events, you still need walls. That’s the bounded context.

A group of logically related events ≈ one bounded context. Objects can look shared across the product, but they behave differently inside different boundaries.

Same object, different meaning

Think of a sandwich.

In a restaurant context, that sandwich is valuable — you pay for it. In a dustbin context, the same sandwich is garbage — you don’t. Boundary means the meaning and rules change with the environment. Roughly like polymorphism, but for the domain model: the thing behaves differently depending on where it lives.

Contexts should also be independent of each other. Interdependent “boundaries” aren’t really boundaries.

Chat example — three contexts

From a simple chat flow you might group like this.

User management — register, login, logout. Dig a little and you also see authentication, authorization, roles and permissions (admin, normal user, maintainer, maybe an assistant/bot). All of that is managing the user.

Message — sent, delivered, deleted, edited. The work is about the message: who sent it, status, content.

Notification — notifying the user that something happened (sent, not seen yet, and so on).

Notification mentions a user. So should it live inside user management?

Look at the properties. In user management you’re dealing with security-ish properties: auth, roles, permissions. Notification is automated “tell the user about an event” — often keyed by user id and event status. Same user id showing up does not mean same context. Logic and responsibility are different, so notification becomes its own bounded context.

Don’t dump notification into message either just because a message triggered it. Message work and notification work aren’t the same job.

Events → bounded contexts
Chat example
User managementuser / login / logoutauth / roles / permsMessagesent / deliverededited / deletedNotificationnotify sent / unseenstatus updatesSame user id across walls does not mean same context — rules and responsibility do.
Events                          Bounded contexts

user / login / logout  ──►  User management
auth / roles / perms

sent / delivered /      ──►  Message
edited / deleted

notify sent / unseen    ──►  Notification
(status updates)

Context → microservice

Common practice: each bounded context becomes a microservice — user management, message (or message management), notification (or user notification).

A new event shows up later? Check its properties. Match an existing context → put it there. No match → find related missing events and consider a new service.

DDD hygiene while you do this

A little duplication is allowed — notification may need a user id so it knows who to ping (“X sent a message to Y”). That’s fine.

What you don’t want: heavy dependency and constant calls between contexts. If notification can’t work without constant round-trips into user service, you’re drifting toward a distributed monolith — merge, or redesign the boundary.

When not to use this

Don’t invent a bounded context for every noun in the UI. Contexts earn their wall when rules, language, and lifecycle diverge.

If two “contexts” always change together and share one model, keep them as modules inside one service until the seam is real.

Production pitfall

Shared kernel that quietly becomes the whole company. Teams allow “just a little” shared user model across every service, then every change to User breaks three deploys. Prefer explicit, small contracts (ids, events) over a growing shared domain object.