typescriptdomain-driven-designnestjscqrsevent-sourcing

Nestjs Event Sourcing - Event Persistence


How is event persistence handled in Nestjs? It's not clear in the documentation (Read the CQRS Recipe), how we should persist events and how we reply them using snapshots. Its also not clear how to create the read side separated from the write side.


Solution

  • The documentation states "To facilitate [the CQRS] model, Nest provides a lightweight CQRS module.", and that is exactly what it offers. Unlike the rest of NestJS the small cqrs object model is not all that opinionated, leaving a lot of architectural decisions for the implementer.

    So the object model allows a clean way to create Command, Saga, Query and Event objects and provide handlers for them, define AggregateRoot entities and having messagebuses for publishing, but not much more. Leaving you with the basics for doing domain-driven design.

    How you integrate them is entirely up to you. If you do a Github search on 'nest + cqrs' you'll find many different approaches. Some choices being e.g.:

    Your question about persisting events refers to the last point, and hints to implementing Event Sourcing (ES) on top of CQRS. Note that doing so is entirely optional. While ES comes with a lot of interesting features, you should only apply this pattern if your application requirements warrant it. ES comes with additional complexity, that should not be underestimated. So reading up on the pros and cons is definitely advised (the cqrs.nu FAQ is a good starter). Note that you can just implement CQRS and add ES later, when the need arises.

    So Event sourcing (and event persistence) are not part of the NestJS CQRS module. When you decide to persist your events you can use a specialized database such as Eventstore or you can implement it in your relational db (see for Postgres e.g. Event Storage in Postgres, PostgreSQL Event Sourcing or full-blown project message-db).

    With Event Sourcing your setup may look like what's described in the good article Event-Sourcing with NestJS by Eliran Natan:

    NestJS Event Sourced CQRS Architecture Concept

    In this setup you have to make projections to load a - usually - relational DB with denormalized views for the read-side of your architecture. Without ES this may not be needed, and you can use your ORM or direct SQL queries to hydrate your Query objects with appropriate data.

    So that's about it. One last tip is to never make direct calls to your read-side logic from write-side code (a recipe for trouble as it destroys the command/query separation).