Best practices for using Command handlers


In the documentation it’s explained that you can either have a separate command handler class, or you can put @CommandHandler annotations on the aggregates, and since I’m new to this, I wonder what are the consequences (positive/negative) of choosing either way?

For example: Would a good advice be to put a @CommandHandler on the constructor of an aggregate to create the actual aggregate, but to have a separate command handler class to handle all other commands?

I can for example also see that the Axon-trader app is not making use of @CommandHandler on constructors of aggregates, and also have distinct command handler classes instead of having @CommandHandler annotated methods.

Should we consider the Axon-trader application as a source of best practises, overriding any examples in the documentation? It’s kinda confusing and overwhelming when I’m new to Axon and CQRS and try to apply best practices to the code from the beginning :slight_smile:

The use of @CommandHandler on constructors of aggregate-roots is quite new, and I think Axon Trader just hasn’t been updated to do it that way yet.

In my experience the Axon documentation is superb (some of the best I’ve ever seen) and it is kept well up-to-date, so you should prefer that over examples if there is ever a conflict. Any such conflict is probably just because of a bit of version skew, like in this case with Axon Trader.

It seems to me (and I am not an expert) that the choice of where to put a @CommandHandler method should be made for each command independently. It very much depends on the nature of the command. You might consider:

  • Whether the command is really specific to just one aggregate-root instance, or whether it has wider reach. Does the command mention the ID of one aggregate-root, or more than one? (Although even if it mentions more than one, one of those IDs might still be the “natural” @TargetAggregateIdentifier).

  • Which other objects the command-handling method will need so that it can do its job. If some of these seem like things that an aggregate-root shouldn’t really get hold of, i.e. if the injection “feels awkward”, then consider using a separate (non-aggregate) handler for that command.


As an “expert” :wink: I can confirm that Richards view is totally correct (including the part on documentation vs samples).
The @CommandHandler on aggregate methods is merely there for convenience. I noticed in my own project that most of the command handler methods looked like:

void doExecuteCommand(SomeCommand command) {
MyAggregate aggregate = repository.load(command.getSomeIdentifier();
aggregate.doSomehting(command.someParam(), command.someOtherParam(), etc…);

So I wondered, why can’t Axon do the “load” part and pass on the command to the aggregate directly?

As soon as you need to do things that feel out of place in an aggregate command handler, move it to an external class. It’s perfectly fine to mix an match the two forms. In my project, I place the command handler classes right next to the aggregate class they belong to.

Hope this helps.


Thanks for feedback:)

Given that I want to test that when applying a @CommandHandler on a constructor works, and that a given event is fired, how do I do it? I think that I should use fixture.givenCommands( new CreatePurchaseOrderCommand()).when(???).expectEvents(new PurchaseOrderCreatedEvent(???));

See complete example here:


  1. What should I put in the when? To me, it doesn’t seem to be needed since the aggregate itself has the commandhandler?!
  2. Since the identifier is generated in the constructor of PurchaseOrder and passed into the event handler, what should I give as input to the constructor in the test?

I might have misunderstood some basic concepts here, so it might be implemented in wrong way, so please advice me on how to proceed :slight_smile:


Hi Viggo,

I'm reasonably new to Axon as well so I don't know whether these are best practices but this is how we do it:

       .when(new CreateCommand("ID1"))
       .expectEvents(new CreatedEvent("ID1"));

In my experience with other test frameworks and methodologies the "given" should be used for prerequisites, the "when" should be used for the action under test, while the "expect" should be used for the expected result.

Seeing as the command which creates an aggregate is the action under test I would think a similar approach to ours would be appropriate. For tests in which you expect an existing aggregate to exist (as a prerequisite) you could put the CreateCommand in the given().

See this article for some more background information on BDD/given-when-thens:


Dennis Laumen

Dennis, thanks for valuable input. The only issue I have with it, is that the ID is generated in the @CommandHandler annotated constructor, which makes it hard to test it the way you describe. Allard, do you have additional input on this?

Hi Viggo,

I always use client generated identifiers. When a client needs to create an aggregate, it generates the identifier itself.
Alternatively, you could inject a mock/stub id generator in your aggregate for testing purposes.



Another alternative, and we’ve done for our tests, is to use a custom identifierfactory that always generates the same identifier value.


Just to weigh in on discussion around putting @CommandHandlers in separate classes or in the AggregateRoots themselves, I have taken the preference of putting them ALL on my AggregateRoots in my toy axon app that I am working on. I find it to be a lot more minimal and removes one more abstraction/layer from your system - CommandHandler classes are kind of like a “service” layer. This way you don’t risk EVER having business logic anywhere else other than your domain aggregate roots.

William, I tend to agree with you. From my minimal experience with CQRS/Axon, it seems more like an unnecessary layer. At least until I know more about the domain I’m modelling, I think I would like to keep all the business logic in my AggregateRoots, and rather refactor them into separate command handlers classes later.

I guess it will never hurt to keep it simple in the beginning :slight_smile:

+1. This is the reason this feature ended up in Axon. I discovered that (in the ideal world, which is the world I try to live in), Command Handler classes do nothing but loading an aggregate and calling a method on it using the values inside the command.
With annotations on the aggregate, Axon implements that feature that’s otherwise just taking up lines of code for you yo maintain.



After gaining some more experience using this framework in the “real world” (I like to think I live here too!) I’ve tried to come up with a rule-of-thumb for when a separate command handler is needed.

As you might expect after reading the CQRS literature, we’ve found it is best when there is a 1-to-1-to-1-to-1 relationship between user interactions (“button click”), commands, aggregates, and atomic transactions (units of work). But a user interaction is not always as clean as the domain methods in the aggregate root. For example, it is hard to get away from some forms with a single giant “Save” button that is doing multiple things in the domain at once. Also, since commands are where JSR 303 bean validation occurs, the commands’ inputs should be amenable to mapping error messages back to the UI. (Imagine a world, hopefully “real”, where “amenable” doesn’t mean “tightly bound to” :-))

So the rule is:

  • Use @CommandHandler on a private method in the aggregate root when the user interaction is 1-to-1 with the user intent. With a task-oriented UI, this should be the majority of cases.
  • Example: “DeleteMyAggregateCommand” (one “delete” button in the UI, one intent => one command, one method => no separate command handler needed)- Use a separate @CommandHandler in pretty much any other situation…(after losing the argument with your UI designer or business owners)
  • Giant “Save” button in the UI, which is expected to be a single atomic transaction. Command handler maps data from the command the aggregate’s methods’ parameters, and calls multiple methods.
  • Command that for whatever pragmatic reason has raw inputs straight from the UI, for example Strings instead of type-safe values, or flattened properties instead of value objects like “amount + currency” instead of “money”. Command handler does some simple lookups or mappings into the domain.
  • A single “Save” command instead of separate “Create” vs. “Update” commands. Command handler does a “find or create” before invoking the method(s).
  • “Create” command that needs to create a particular subtype of aggregate based on the data.
  • (A single command directly affecting multiple aggregates would require a custom command handler, however you should never do this.)
    Arguably all of these cases are really for UI-specific needs, so to keep separation between UI and domain, I find it is almost always the case that separate command handlers as part of the UI “layer”, not the domain at all.


Great insightful write-up Peter, thanks!

Peter said:

  • A single “Save” command instead of separate “Create” vs. “Update” commands. Command handler does a “find or create” before invoking the method(s).
    What’s the best way to do this kind of “find or create” behaviour in Axon?

It seems problematic at the moment, because the repositories don’t have a method for it; a single “CreateOrUpdate” command can’t be bound to both a constructor and a normal method of an aggregate-root; and perhaps another transaction could jump in between the “find” and “create” steps in a non-aggregate command handler.

I think (but I’m not certain) that it should be transactionally safe to use a small query-side model in a non-aggregate command handler to decide whether to create or update a given aggregate. But it’s seems awkward, and I think it’s only safe if there’s only one command handler that ever has to make that decision.

Obviously I would prefer to only have separate Create or Update commands, but I think there are many cases where that isn’t practical. For example, some of my aggregates reflect external state in a legacy system which can only be polled statelessly. If that external system starts reporting some additional state, my system doesn’t know whether that is genuinely new state, or just state that we haven’t seen for a while, unless we do some kind of lookup in our own system – basically, “find or create”.


Hi Richard,

you’re right about the “separate Create or Update commands”. They are preferred over the find-or-create approach, but it’s not always possible to work around them.

To implement find-or-create in Axon, you need an “external command handler”, which is a normal bean with an @CommandHandler on it. You command handler code would look like:
try {
aggregate = repository.load(aggregateid)
} catch (AggregateNotFoundException e ) {
aggregate = new MyAggregate(…);

Having to catch an exception may not seem like the most beautiful approach, but then again, find-or-create isn’t very beautiful if you look at it from a DDD/CQRS perspective.

Also consider, as you mentioned, an approach where you do a query in the query database to find out if you need to do an update of a create. This model may be eventually consistent with the command model, but the chance of false positives/negatives is still extremely small.



Thanks Allard. I guess the repository.add(aggregate) call might also throw some kind of “aggregate already exists” exception, in which case we do the update call instead.

Since this little snippet of code will pretty much always be the same for the “find or create” case, would it make sense for the command bus (or something) to support it, e.g. something like commandBus.createOrUpdate(createCommand, updateCommand) ? Hmm… it looks a bit clunky… I’m really not sure.


Hi Richard,

the add method doesn’t really access anything until the transaction commits. It will therefore only throw an exception when it’s really too late to do anything about it.

As the create-or-update approach isn’t a proper CQRS solution, but mainly a workaround for someone else’s problem, I’m not really planning to create an API for it. Such an API would only make it look like a best-practice.


Fair enough – that seems very reasonable!

Cheers :slight_smile: