I'm developing real-time chat functionality as part of an application. As per my initial structure I had 3 Domain Objects as part of this new context:

  • Thread (aggregate root)
  • ThreadMessage (entity, part of the Thread aggregate as a collection; has a ParticipantId to know it's sender)
  • ThreadParticipant (entity, part of the Thread aggregate as a collection)

The problem arose when I realised I need the Thread and ThreadParticipant relationship to be logically (and in the persistance store) many-to-many. My User (from the Identity bounded context) will hold a reference to a ThreadParticipant's ID.

The more I thought the less sense it made for the ThreadParticipant to be a child entity in Thread as it it can obviously live on it's own being in a many-to-many relationship with Thread.

My question is is it bad to create a separate bounded context with ThreadParticipant as the aggregate root, which will hold a collection of Thread IDs, for example. And if so, what will happen to the Message entity from the Thread aggregate root- it will hold a reference to the Participant aggregate root which will cause a circular reference between both contexts.

  • 1
    Don't confuse aggregate roots with database records; they're not the same thing. This probably all belongs in a single root. Commented Aug 3, 2020 at 15:15
  • I know that the persistance is a detail that should not interfere and the domain should not care about. Could you elaborate on your comment? Commented Aug 3, 2020 at 15:25
  • It's a chat program, not an enterprise system. Your aggregate root is essentially void main() Commented Aug 3, 2020 at 15:27
  • It's not a chat program, I don't think I've stated that anywhere. Chat functionality is just a component Commented Aug 3, 2020 at 15:28
  • Well, regardless, the chat system is a module. If you want to call it an aggregate root, that's fine, but that's as fine-grained as I think you need. Commented Aug 3, 2020 at 15:32

1 Answer 1


There are no issues in having a many-to-many relationship between Theads an Participants. The decision is not about the relationship but instead about the consistency that you want to enforce.

  • Should you be able to retrieve all threads and look at their participants?

  • Should you be able to retrieve all participants and look all their thread?

  • given a participant, should you be able to access all threads info even if a thread as been deleted?

  • given a thread, if a partcipant changes its nickname after joining, should you still be able to watch old nickname into thread participants list?

well these are the questions that make you understand if thread and participants are two different aggregates. If so, they should be as loosely coupled as possible

Final note about bunded context: as of now, we've talked about information consistency and we have used aggregates to define boundaries around those consistent information. Bounded Context are not the same as aggregates. Aggregates enforce logical consistency, bounded context enforce semantic consistency. You could have multiple aggregates in a bounded context, but each aggregate has its unique meaning in this context. You've choose to have "Users" and "Participants" into your application. Well, it's clear that a Participants IS a user, but in the identity BC, being a user means to be identified in the system, in chat BC being a users means interact with other users. So, same concept, different meaning, but you're still interested on keeping some form of consistency between the two BCs

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.