---
title: 'CHR0021: Event types should be record types'
---

## Rule Description

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

## Severity

Warning

## Example

### Violation

```csharp
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; }
}
```

### Fix

```csharp
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:

```csharp
using Cratis.Chronicle.Events;

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

## Why This Rule Exists

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

## Related Rules

- [CHR0012](/chronicle/code-analysis/chr0012/): Event types should avoid nullable properties
