Skip to content

Event source

An event source is one entity or process in your domain: a person, an account, an order, a transfer. All the state changes of that entity are events, and the event source id (EventSourceId) is what binds them together. It is comparable to the primary key of a row in a database.

For instance, take the notion of a person. What identifies the person uniquely is in many systems the social security number assigned by the government. All state changes relevant for an instance of a person are identified by that one value, which is the event source id.

The diagram shows two event sources, two people, each with its own ordered story of events, all sharing the same event source id throughout:

EventSourceId: person-456

PersonRegistered

NameCorrected

EventSourceId: person-123

PersonRegistered

AddressChanged

PhoneChanged

When you append an event, the first argument is the event source id. Every event has exactly one.

Four values that describe where an event belongs

Section titled “Four values that describe where an event belongs”

Every stored event carries four routing values. Two identify the entity and two identify a part of its story.

ValueAnswersExample
EventSourceIdWhich instance?account-42
EventSourceTypeWhich kind of event source?Account
EventStreamTypeWhich named part of the story?Transactions
EventStreamIdWhich instance of that part?2026-04

The last three are optional. An event appended with only an event source id has the default event source type and the default stream, and that is how Chronicle has always worked. All four are indexed, filterable, and the dimensions a concurrency scope can narrow to.

A stream is a named part of an event source, such as the transactions of one month, or the onboarding of an account. It is not a separate entity: its events belong to the same event source and share its event source id. The stream type names the part, and the stream id picks one instance of it.

You can leave the type and stream values as strings you pass on each append. Or you can declare them once, as a type that implements IEventSource:

[EventSource("Account")]
[EventStream("Onboarding")]
[EventStream("Transactions")]
public class AccountEventSource : IEventSource;

That type is an event source definition. Its name becomes the event source type of events appended through it. Each stream’s name becomes an event stream type. The definition also declares which of the four values take part in the concurrency check of an append, per event source and per stream.

A definition does not list event types, is never instantiated, and does not replace the event source id: one definition serves every instance. The client discovers definitions, registers them with the kernel, and both sides check appends against them. Everything about them, from declaring one to how Chronicle uses it, is in Event sources and streams.

ValuePart of a concurrency scopePart of a decision read’s guard
Event source idYesYes. It is the key
Event source typeYesOptional narrowing
Event stream typeYesOptional narrowing
Event stream idYesOptional narrowing
Event typesYesYes. The event types of the read model
TagsNoNo

The first four values are the stream metadata, and they play the role that tags play in DCB. Tags are labels you can filter and categorize by. They do not take part in consistency. An event has one event source, so a fact that concerns two entities is written as two events, one per event source, in one atomic append. Dynamic Consistency Boundary in Chronicle explains what that means for DCB.