Merge two aggregates

Hello everyone,

As it happens quite often with software projects you take a bad architectural decision in the beginning and then it keeps coming back and biting you. In our case we have created two separate aggregate roots that handle related events and nowadays is clear that what we should have done instead is to create a single aggregate root with multiple entities e.g.


  • AllocationsRegistry (Aggregate root)
  • AssignmentsRegistry (Aggregate root)

while we need:

  • Registry (Aggregare root)
    has an AllocationsRegistry (AbstractAnnotatedEntity)
    has an AssignmentsRegistry (AbstractAnnotatedEntity)

So, the question is: how do you merge two aggregate roots? Does anybody has previous experience doing so? Any other insights?


Hi Yannis,

the only way to get this done is through a script that you need to run once to upgrade.

You roughly need to follow this process:

  • make sure you have a new aggregate identifier for the new combination of Entities. Thus two aggregate identifiers of the old situation should result in a single new one.
  • make sure you can re-order the combined events of the two event streams into a single stream
  • find out if you can roughly keep the same event structure in the new situation (see below when that is not the case)
  • make a backup of the old event streams
  • translate each old event into a new one. This mainly involves changing the value of the “aggregateIdentifier” field to the new value. Perhaps you need to add a new reference to the entity id. It is probably easiers to do this translation using XML transformation. You can use the “EventEntryStore” to load the actual (XML) contents of the Event Store, or manually access the DomainEvents table using JPA.
  • in each entry in the DomainEvents table, update the Event to the new format, and set the correct aggregateIdentifier, type and sequence number.

Since you’re modifying the contents of the event store here, it is important to make a backup of the old events.

If step 3 shows that the event structure also needs to change, you can also take another approach. This has been previously done at a project here at Dutchworks (in which I am not involved, by the way).
For each Event related to one of the old aggregates, fire a command that should trigger a similar event for the new aggregate. To make sure timestamps are correct, you could use JodaTimeUtils.setCurrentTimeMillis (or setCurrentTimeOffset) to set the Event’s timestamp as the current time. This will generate a new set of events, while keeping the old ones intact.

Hope this helps.

I acknowledge that this process isn’t very straightforward. I have gotten a lot of feedback from the project here that needed to migrate quite a bit of information, as well as from this mailing list. I have used that as input for the new “Message vs. Event” based model. Therefore, in Axon 2, migrating events from one aggregate to another should be much simpler and will (in most cases) only involve changing some index information in the Event Store.