Skip to content

CHR0021: Event types should be record types

Types decorated with [EventType] should be declared as record types rather than classes.

Warning

using Cratis.Chronicle.Events;
[EventType("b5e21a5f-1234-4c3e-9b99-aabbccddeeff")]
public class UserRegistered // ❌ mutable class
{
public string UserId { get; set; }
public string Email { get; set; }
}
using Cratis.Chronicle.Events;
[EventType("b5e21a5f-1234-4c3e-9b99-aabbccddeeff")]
public record UserRegistered(string UserId, string Email); // ✅ immutable record

Or with init-only property syntax for events with many properties:

using Cratis.Chronicle.Events;
[EventType("b5e21a5f-1234-4c3e-9b99-aabbccddeeff")]
public record UserRegistered
{
public string UserId { get; init; }
public string Email { get; init; }
}

Events in Chronicle are permanent, immutable facts appended to the event log and replayed to rebuild read-model state. Using a class allows the event object to be mutated after creation, which can lead to subtle bugs—for example, modifying an event during a handler before it is fully processed, or producing different results across replays.

Using a record type provides:

  • Immutability by default — positional parameters are init-only
  • Structural equality — two events with the same data are considered equal
  • Concise syntax — positional record syntax keeps event definitions compact and self-documenting
  • Intent clarity — a record signals to readers that the type is a value/fact, not a mutable entity
  • CHR0012: Event types should avoid nullable properties