Domain events: simple and reliable solution

Today, I’d like to write about a simple and reliable way to implement domain events.

Domain events: dispatching before committing

I believe it was Udi Dahan who first introduced the concept of domain events specific to Domain-Driven Design. The idea is simple: if you want to indicate an event that is significant to your domain, raise this event explicitly and let the other classes in your domain model subscribe and react to it.

So basically do the following. Create a domain event:

Then introduce a static class that will allow for subscribing to the events and raising them:

Now as you have this infrastructure in place, you can start using it. This is what a domain event producer can look like:

And this an example of a consumer. It gathers statistics for all submitted orders and saves it to the database:

I will call this classic approach to domain events dispatching before committing. That’s because it allows you to raise and react to an event before the business transaction is committed.

There are several problems with this approach. It can be useful at times but falls short when the side effects of processing the domain events span across multiple transactions.

Let me explain what I mean by that. Let’s say for example that you want to add another consumer to the above domain event. This consumer would send notification emails to users who submit their orders:

Now, the act of sending an email brings one more transaction to the table. Before that, both the producer of the domain event and the consumer of it generated side effects that were stored in the same database. The side effect of the producer was the Order class instance, and the side effect of the consumer was changed stats info. You could create an overarching database transaction so that if the system fails to persist the order for some reason, the changes to the order statistics would not be persisted either.

After adding the OrderNotification class, this is no longer the case. Sending emails works within its own transaction boundaries and you can’t tie it to the database one. By sending notification emails before ensuring the database transaction is completed, you are opening the application for potential inconsistency issues. Now it is possible to have an email sent without persisting the order. Which could happen if, for example, the database goes down at the time of saving that order.

Some people argue that, sure, this approach would not work in such scenarios, but you are still able to use it when there are no external systems involved. In other words, if all consumers operate within the same database transaction scope, like OrderStats.

This is a poor argument. If all the consumers of an event reside within the same database transaction, domain events add very little value. If all the collaborating parties operate upon the same database, it’s better to make the flow of the domain logic explicit and avoid dealing with domain events. Domain events bring significant complexity overhead in the form of indirection. If you are able to avoid this overhead, I advocate you do that.

So, if OrderStats is the only consumer of the OrderSubmitted event, you can re-write the example above into something like this:

and get rid of the domain events infrastructure altogether. This program flow gives a much better understanding of what is going on during the request. All steps are outlined explicitly here.

This is the reason why I don’t recommend using the “dispatch before committing” approach. It cannot be used if consumers produce side effects that lie outside of the database transaction scope. And for all other types of side effects, you would be better off not using domain events anyway.

When it comes to the topic of domain events, the general rule is this: employ them for inter-application communication only, when you need to incur side effects that span beyond just your database. For inner-application communication, get your program flow straight and explicit. Use regular techniques, like returning a result of an operation and passing it to a next method.

Jimmy Bogard wrote about another domain events pattern a few years back. The difference between Udi’s and Jimmy’s approaches is that the latter suggests separating the two steps that comprise raising a domain event: creation and dispatching. It makes the events more testable but essentially, it is the same “dispatch before committing” approach: domain events get dispatched before the database transaction is committed.

Domain events: committing before dispatching

A couple years ago I too wrote about domain events in my Domain-Driven Design in Practice training course. I called my implementation “a better approach” for the lack of a better name. But now I would like to rename it to committing before dispatching.

As you guessed from the name already, this approach involves committing the database transaction and only after that dispatching domain events. The basic idea is similar to what Jimmy Bogard described in his blog post: you shouldn’t dispatch the events right away and instead need to keep track of them until you are ready to commit the database transaction. The main difference here is that you dispatch those events after the transaction is committed, not before.

Here’s what the producer of the event would look like:

Note that Order no longer works with the static DomainEvents class to dispatch those events. Instead, it saves them to the internal collection. By the way, this opens an opportunity to also merge events into a single one or cancel previous events. Which wasn’t possible with the previous approach because the events were dispatched right away.

To dispatch the events, I used NHibernate’s event listeners. Particularly, those events that trigger after the database transaction is committed (taken from here):

This ensures that the dispatch will be executed only after the data is persisted. Note the OnPostUpdateCollection listener in the code above. It allows you to dispatch events even if the entity itself has not been changed. For example, when you add a line to an order but keep the order itself unchanged. Took me long time to figure out how to deal with those use cases 🙂

The “commit before dispatching” approach is a big improvement over the “dispatch before committing” one. Now you are able to incur any side effects in your domain event consumers, be they sending an email, putting a message on a bus, calling a third-party API, etc. You will no longer run into a situation when your database transaction fails but the confirmation email is already sent to the customer.

Domain events: simple and reliable solution

However, even with this improvement, there still are two drawbacks to that solution:

  • You need an ORM to implement it. And not just any ORM but the one which supports post-update, -delete, etc events. NHibernate is great at that but maybe you can’t use it for some reason.
  • You can still run into inconsistencies. They are not as severe as those you encounter with dispatching before committing but they still can happen. If your email grid fails to accept the notification email, you will end up with a submitted order but with no confirmation email. You can’t make the dispatch of domain events 100% consistent with committing the database transaction.

I’m saying that such inconsistencies are not as severe because it’s pretty easy to mitigate them. A reliable queue on top of external, potentially faulty calls helps a lot. It significantly reduces the chances of running into the inconsistency (but of course doesn’t eliminate it completely because the reliable queue can also potentially go down).

So what is that simple and reliable solution that doesn’t have all those drawbacks?

It’s persisting domain events along with domain objects. What you need to do is add a table to the database:

Domain events: simple and reliable solution

Domain events: simple and reliable solution

and persist events into it like regular domain objects. Then, have a separate worker that picks those events one by one and processes them. In most cases that processing would involve pushing a message on a bus which then can fan it to the appropriate subscribers. But you can also come up with your own pub-sub mechanism.

The benefit of this approach is that you now have a 100% certainty in your domain events infrastructure. Persisting domain events allows you to achieve full consistency between the producers and consumers of those events. Producers are able to generate events only if they themselves are persisted (Order class in the example above). And consumers have a chance to implement a retry mechanism so that no domain events slip through the cracks. It also helps that the consumer resides in a separate process.

There’s one drawback to this approach, though. It requires more effort to implement compared to the previous one. It’s simple and reliable, but not easy. You will need to introduce the additional table and you will also need to develop a background job for that purpose.

I usually go with the “committing before dispatching” approach. All my event consumers usually do is put a message on a bus anyway, which is a quite reliable operation. I haven’t had any issues with it in production. But the manual approach is good too, especially taking into account all the benefits I described above.


  • Use domain events for inter-application communication only. For inner-application communication, use explicit program flow instead.
  • Dispatch before committing is when you dispatch an event before the database transaction is completed. Avoid this type of domain events as you won’t be able to use it for inter-application communication.
  • Commit before dispatching is when you dispatch an event after the database transaction is completed. This approach is good in most cases. There’s still a small chance of inconsistency with this implementation.
  • Persist domain events along with domain objects if you need 100% consistency and can’t use an ORM. This approach requires more work.

Be sure to check out my Domain-Driven Design in Practice training course if you want to learn more about DDD in general and domain events in particular.


  • cminor

    Hello Vladimir,

    I would like to thank you for the interesting post. Some comments from my side:
    The approach you are proposing is not really new, in fact this is exactly how you code and persist event sourced entities. Although in your case you still have a Memento pattern going on (the OrderLine) you can easily fit this item into an appropriate event and in the end you can persist (and rebuilt) your model only from events. This will greatly simplify your data layer (no need for ORM at all, Repositories will only need to have 2 methods: fetchById and save) but sometimes it creates a bit of complexity that not all teams want to deal with. Lastly as far as publishing an event is concerned, the approach is not different than Committing and Publishing. It is the exact same thing but instead of synchronously publishing the events after commit, you are doing it async. As with all other great tools async comes with a cost, so we must really do our analysis and decide how much we want to invest in this compared to how much we will gain by adding another component-worker to the game, or just play synchronously even though there always is the chance that the highly available, robust & scalable Messaging Fabric might fail 🙂

    • Vladimir Khorikov

      Thanks for the comment, great points.

      I’m not claiming the authorship of this idea, most ideas in programming has already been invented anyway 🙂 And indeed, it’s a step towards an event sourced architecture.

      Regarding that the last approach is not different than Committing and Publishing other than being async. Well, that’s the whole point, it’s the only way to ensure full consistency.

    • Tilman Linden

      Agree that this goes towards event sourced architecture. However, the relational model (be it ORM-based or whatever) + event table approach still has the difference that you already have your read model written consistently. In a pure ES system, the read model updates come on top. Of course this brings benefits also, as you can have multiple read models etc, but probably sometimes you don’t need that extra flexibility.

      Additionally, the approach to add domain events to a traditional relational DB based persistence layer can be helpful to introduce reliable domain events into legacy applications. I found that often times you can find some way to add domain events to existing DB transactions that update the legacy model, and by that you get a very good basis to incrementally escape a legacy situation.

      Vladimir, great article, only found your blog today and will for sure return in the future!

      • Vladimir Khorikov

        Thanks and welcome!

  • Danil Suits

    It sounds as though you are advocating the pattern that Udi described in 2014?

    • Vladimir Khorikov

      Similar approach, indeed.

  • Krzysztof Sierżęga

    Hello Vladmir,
    Check this solution for dispatching events after transaction successful. We are using it and it also works great 🙂

    • Vladimir Khorikov

      Looks interesting, didn’t know about that feature. Will try to play with it, thanks

  • Christopher McEwen

    Nice post Vladmir 🙂

    I’m quite new to DDD and was wondering in your scenario, for dispatching before committing, wouldn’t you just expect both events to complete eventually?

    So our handler for saving the data to the database would just keep retrying (Message Queue) and so would our email handler. Eventually both would be complete.

    Or implement a two step check where the handler for sending the email checks the record is in the database before it sends the email. If the record isn’t in the database then it sits on the queue and retries.

    Is this not a viable workaround for dispatching before committing?

    • Vladimir Khorikov

      The problem is that if you dispatch events before the action they are generated by is committed, the event processors can’t check anything as there’s nothing in the database yet.

  • AreQ_BAH

    Commit before dispatching implementation:
    What about using your app service for raising an event? There you will be sure, that it will ocure after entity was saved to the DB. And you dont need to leverage AOP – whitch is introducing a bit of ‘auto-magic’ into the workflow.

    • Vladimir Khorikov

      You can do that but that would be a lot of repetitive code as you’ll need to put it to every method in your app services. It is a viable option for simpler code bases, though.

  • Hristo Yankov


    Can you elaborate on the use of domain events in “inter-application” development? I just don’t see it. If two applications know about the same domain event, in my view they are just separate components of the same application. OK, that’s arguable. But how would you send the domain event to another application? It would require some kind of infrastructure – a Queue, database record, http connection, whatever … I mean, that would go way outside the simple Subscribe and Post notification, shown in this post.

    More importantly, I was under the impression that DDD pushes persistence to the very edge of the implementation and makes it a minor, if not even an optional concern. Your last approach suggests that we NEED persistence, in order to have Domain Events, no? Don’t get me wrong, I like it, I am just trying to understand the implications.

    Great post, nonetheless!

    • Vladimir Khorikov

      Regarding the inter-application communication. It basically means that the event handlers incur side effects that don’t lie within your main data storage. It can be a call to the SMTP service to send an email or a call to the bus to submit a message to the publisher.

      Inter-application communication doesn’t necessarily mean that you have two business applications/microservices that communicate with each other. You can do that if your handlers call other microservices/apps directly via their APIs but that wouldn’t be a good solution. Usually what happens is your handlers reach out to a queue/bus. So communication here is between your app and the bus, not between your app and the downstream apps. What happens with the messages you put on the bus afterwards is not your app’s concern.

      If two applications know about the same domain event, in my view they are just separate components of the same application.

      If by domain event you mean the actual domain event class then yes, I agree with you. Two different code bases shouldn’t couple to the same domain even implementation unless they belong to the same bounded context. However, it’s OK for two apps to couple to a data contract, which is the format of the messages that travel between applications. You need to know how to interpret them in order to communicate with other apps.

      Regarding persistence, I don’t see a contradiction here. You do make the domain model agnostic to the fact that all its entities/value objects/etc are stored somewhere. Similarly, your domain event handlers don’t have to know where the events they are processing come from. Just like a User entity doesn’t need to know that it is stored in a relational database. The persistence concern is still there, it’s just separate from the domain logic.

  • Harry McIntyre

    The bit about not using them for inner-application development is very important – the code-base I’m working on uses them for internally raising behaviour, but all it has done is obscure what happens.

    In your above code, what happens if the post-commit code fails? I would have thought that it would be better to use a pre-commit hook, AND only write services which support transactions (so that the change can be rolled back along with the rest of the unit of work). Otherwise you might not end up sending that password-reset email, right?

    • Vladimir Khorikov

      uses them for internally raising behaviour, but all it has done is obscure what happens

      I would compare them with regular .NET even handlers. Those events are good in some scenarios (like handling events from the UI: button click, etc) but definitely not in the domain model.

      That’s correct, if the post-commit fails, you will end up not sending the email. I don’t think a distributed transaction is a good option, though. Too much overhead in order to setup and run it. I would prefer putting a (more) reliable external system in front of the SMTP server instead, like an Azure queue or an AWS SNS/SQS.

  • Julio Gonzalez

    Hi Vladimir,
    Thanks for the interesting article. Wouldn’t you prefer a messaging infrastructure with guaranteed delivery (Rmq or similar) rather than your approach of persisting domain events along with domain objects? I don’t see the need of storing the domain event on DB and having something constantly polling it?

    • Vladimir Khorikov

      I would. I personally prefer not introducing this additional complexity of keeping the domain events in the database and usually go with Commit before Dispatch. The chance of failing to send a domain event is low enough, so trading that chance for simpler code is usually worth it.

  • Antonio Castro Jr

    Hi Vladimir,

    For a long time I’m looking forward a solution on implementing domain events, but I always find a “but”. I’m using EF core in my solution. Is it possible to have the same results with this ORM or only with NHibernate?

    • Vladimir Khorikov

      EF does support similar functionality with its SavingChanges event but, admittedly, it’s not as rich as in NHibernate. Still better than raising events manually, though.

  • Anderson GM

    Hi Vladimir,

    I couldn’t see how persisting the events would result in full consistency between the producers and consumers. Can I ask you to elaborate it a bit better please?

    I understand that way you can use the same transaction to persist the domain objects with their events, but in the moment you try publishing those events you are again in the same situation. I mean, I think you need to read the record in the database, mark the record as published and effectively publish the message. So again, publishing the message can potentially fail and you already marked it as published.

    Am I missing something here?


    • Vladimir Khorikov

      There are 3 possible gradations of reliability in messaging: “at most once”, “at least once”, and “exactly once”. With the “before” solution from the article, we have the first stage – at most once. It means that the message is sent once at best. At worst, it’s not sent at all.

      With the advancement described in the article, we promote the reliability to the “at east once” level. (Note that you need to first send the message and mark it as sent or delete it only if it is successful, not the other way around as you described, otherwise that would still give us “at most once” level of reliability.) In this case, you guarantee that the message will be sent once at best, but you also have to accept that it could be sent multiple times if something goes wrong between successfully publishing it and marking it as published / deleting it.

      Finally, the “exactly once” level can be achieved only when the receiving part also implements a storage of all messages it has processed, in order to weed out the duplicates, it can’t be achieved solely by the sending part.

      You are right that the solution from the article is not 100% reliable but it’s enough in most cases assuming that the messages are idempotent (can be processed by the receiving part multiple times without damaging consistency).

      • Anderson GM

        Thanks for the explanation. Now I see your point of view.

  • camainc

    Finally, an article on domain events that actually makes sense to me. Thank you!

    I especially resonate with the advice about not using domain events for behavior within a context, and reserving events for inter-application communication.

  • Boudewijn Geiger

    Hi Vladimir. How would you raise an event before an entity is deleted?

    • Vladimir Khorikov

      If you are using an ORM, you can subscribe to the appropriate event. If it’s the “raw” domain events implementation, you’d need to save the event along with the entity deletion.

      • Boudewijn Geiger

        In you’re example you raise an domain event on creation (i.e the constructor), But AFAIK it’s not possible to use a destructor for raising events. So where would you raise an event like “UserUnregistered”?

        • Vladimir Khorikov

          In the approach with NHibernate, you’d subscribe to IPostDeleteEventListener from the ORM, it fires after the entity is deleted. With the manual approach, you need to create the domain manually somewhere upper the call stack, the destructor isn’t a good place for that. Something like UserRepository.Delete() should do the job.

  • Rabbal

    Is it possible to return result from an event handler like returning result by command handler in business rule validation scenario? or define a Result Property in DomainEventBase and use it like e.Cancel of FormClosing EventArgs for return result of Operation and finally Raise a DomainEventResult event that has all result of invoked handlers for bubble up to UI for avoid using Exception.

    • Vladimir Khorikov

      Not sure I understand the question, maybe submit a code sample?

      • Rabbal

        Is it a good way to return fail or success result like below by eventhandler? because sometimes one component subscribe to an
        EntityDomainEvent (ex: ProductUpdated ) of other component for check one business rule validation Is Satisfied or not.

        public interface IDomainEventHandler : ITransientDependency
        where T : DomainEvent
        Task Handle(T domainEvent);

        and in the EventDispatcher get result of each handler and finally throw exception if result was failed:

        public async Task Raise(T domainEvent) where T : DomainEvent
        var eventType = domainEvent.GetType();
        var handlerType = typeof(IDomainEventHandler).MakeGenericType(eventType);

        var result = Result.Success();

        foreach (var handler in _container.GetServices(handlerType))
        var method = handlerType.GetMethod(
        new[] { eventType }

        var handlerResult = await (Task)method?.Invoke(handler, new object[] { domainEvent });
        result = Result.Combine(result, handlerResult);

        result.OnFailure(() => throw new UserFriendlyException(result.Message));


  • genisbarrera

    public static void Dispatch(IDomainEvent domainEvent)
    foreach (Type handlerType in _handlers)
    bool canHandleEvent = handlerType.GetInterfaces()
    .Any(x => x.IsGenericType
    && x.GetGenericTypeDefinition() == typeof(IHandler)
    && x.GenericTypeArguments[0] == domainEvent.GetType());

    if (canHandleEvent)
    dynamic handler = Activator.CreateInstance(handlerType);

    Hi, I have a problem with this Dipatch events method. I would like to invoke a constructor that have a parameter that is injected. In your example the repository was a singleton, But, what does it happen if the repo is something like this?

    public class BalanceChangedEventHandler : IHandler
    public BalanceChangedEventHandler(IHeadOfficeRepository repository)
    _repository = repository;
    public void Handle(BalanceChangedEvent domainEvent)

    HeadOffice headOffice = _repository.GetHeadOffice();


    • Vladimir Khorikov

      You need to use’s DI container for that. You can see in my CQRS in Practice course how I do that.

      Here’s the particular location in the course code from that course:

      • genisbarrera

        Thanks for your response Vladimir, you right, i had to use de DI container. Another issue I had it was to get the ihandler types from the assemblies, It was no the same type than the typeof(). I had to use IEnumerable assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList() to get the assemblies in the DomainEvents static class

  • ardalis

    The recommendation against using domain events for pre-persistence purposes fails to recognize certain benefits the pattern brings (which may outweigh the legitimate cost of the indirection they impose). Specifically:

    1. If I have a method on an entity that needs a dependency via DI as part of its process, with domain events I can raise the event and let the handler (which can use DI) perform this work. Without domain events, I probably need to move the behavior out of my entity and into a service, thus making my model more anemic, violating tell, don’t ask, and breaking the encapsulation of my entity and/or aggregate.

    2. If my model raises events in response to interesting things happening in the domain, I can easily add additional behavior in the future without having to touch my existing code. Thus, it helps follow the Open Closed Principle.

    These are the two biggest advantages one gets. Another useful one I’ve taken advantage of at times is raising domain events (I call these aggregate events) from aggregate children and handling them in the aggregate root. This helps avoid the antipattern of shifting logic that belongs in aggregate children up to the root because the root is the place where consistency checks happen. With aggregate events, the behavior lives where it should and handlers in the root can still perform consistency checks.

    I discuss this further here:

  • dave barnett

    Thanks for this, I got loads out of it. I notice that your examples in #7 Domain Events are all synchronous and don’t have a way of reporting failure if it occurs. Is this for simplicity or is there a good reason for this? All my current domain event code is done synchronously as well and I report an error by either by just logging it or throwing an exception that is caught in a try catch when I save changes.

    Idea 1: I wondered could you change the code to be
    await DomainEvents.DispatchAsync(domainEvent). Or you could even go one step further and do something like this

    tasks = domainEvents.Select(de => DomainEvents.DispatchAsync(de)).ToList();

    await Task.WhenAll(tasks);

    Idea 2: I wondered about updating my code so that DomainEvents.Dispatch(domainEvent) returns a CSharpFunctionalExtenisions Result object.

    So the code could look something like this

    Result SaveChanges()
    var domainEvents = getDomainEvents();

    List dispatchResults = new List();
    foreach (IDomainEvent domainEvent in domainEvents)

    return Result.Combine(dispatchResults);


    Are these ideas worth pursuing or are there reasons why I should leave it as you have in your example?