Glossary
A reference for the terms used throughout these docs. If you're new to event sourcing, start here.
Aggregate
A cluster of domain objects that must stay consistent together. In Nagare, the aggregate is the thing that receives commands and decides whether to accept or reject them. If it accepts, it emits events.
A BookAggregate doesn't model "a book." It models the rules around borrowing — ensuring a book can't be borrowed by two people at the same time.
See: Aggregates
Aggregate ID
A string that uniquely identifies one aggregate instance. Every event in the store is tagged with the aggregate ID that produced it.
var aggregate = await repo.Load(new AggregateId("book-dune-1"));Bounded context
A boundary around a set of domain concepts that belong together. An "Order" in the shipping context is not the same thing as an "Order" in the billing context. Each bounded context has its own aggregates, events, and projections.
See: Modular Monolith
Checkpoint
The position of the last event a subscription successfully processed. On restart, the subscription resumes from its checkpoint instead of replaying everything from the beginning.
See: Projections — Checkpoints
Command
An instruction in the imperative mood: "do this." Commands express what someone wants to happen. They can be accepted, rejected, or ignored.
public record BorrowBook(string BorrowerId) : BookCommand;See: Commands & Events
CQRS
Command Query Responsibility Segregation. Writes go through the aggregate (commands). Reads come from projections (queries). The event store sits between the two.
Nagare implements CQRS naturally: aggregates handle the write side, projections handle the read side.
See: Core Concepts
Decider pattern
A formal way to describe an aggregate as three functions:
| Function | What it does |
|---|---|
decide(state, command) → events | Business rules |
evolve(state, event) → state | State transitions |
initialState() → state | Starting point |
In Nagare, RegisterCommandHandlers is decide, RegisterEventHandlers is evolve, and State.Default is initialState.
See: Core Concepts — The Decider pattern
Domain event
See Event.
Enrichment projection
A projection that builds a read model and emits integration events for other bounded contexts to consume. It bridges the gap between internal domain events and external contracts.
See: Projections — Enrichment projection
Event
A fact in the past tense: "this happened." Events are the source of truth in an event-sourced system. Once written, they never change.
public record BookBorrowed(string BorrowerId, DateTimeOffset BorrowedAt) : BookEvent;See: Commands & Events
Event envelope
The wrapper around an event that carries metadata: aggregate ID, position in the global stream, aggregate version, timestamp, and custom metadata (correlation ID, user ID, etc.).
envelope.AggregateId // who
envelope.Event // what
envelope.Position // where in the global stream
envelope.CreatedAt // when
envelope.Metadata // context (correlation, causation, user)Event sourcing
Instead of storing the current state of something, you store the sequence of events that produced it. The current state is derived by replaying those events in order.
Your bank account works this way: a ledger of transactions, not a single balance.
See: Why Event Sourcing
Event store
The append-only database where events are persisted. Events are ordered by position (global) and version (per aggregate). Nagare supports SQLite, SQL Server, and PostgreSQL as event store backends.
See: Store Adapters
Event upcaster
A function that transforms old event formats into the current format at read time. The stored events are never modified. This lets you evolve your schema without breaking existing data.
See: Event Versioning
Eventually consistent
Projections lag behind the event stream by a small delay (typically milliseconds). After an event is appended, projections process it shortly after, not instantaneously. If you need immediate read-after-write consistency, read from the aggregate directly.
Given-When-Then
The natural testing vocabulary for event-sourced systems:
- Given these events happened in the past
- When this command is issued
- Then these new events should be produced (or the command should be rejected)
See: Testing
Idempotency
A command is idempotent when sending it twice produces the same result. In Nagare, use Then.Accept() for commands that are already satisfied — this acknowledges the command without duplicating events.
Integration event
An event published to a message broker (like Kafka) for other bounded contexts to consume. Integration events are coarse-grained business facts, not fine-grained state changes. They cross context boundaries and become contracts.
See: Messaging
Middleware
A handler in the command pipeline that can inspect, enrich, or short-circuit a command before it reaches the aggregate. Works like ASP.NET Core middleware.
See: Middleware
Optimistic concurrency
When two writes target the same aggregate simultaneously, one will fail with WrongExpectedVersionException. The first writer wins; the second must reload and retry. This prevents lost updates without requiring locks.
See: Concurrency
Position
A monotonically increasing number that identifies where an event sits in the global event stream (across all aggregates). Subscriptions use positions to track their progress.
Projection
A function that subscribes to the event stream and builds a read model. One event stream can feed many projections, each shaped for a different use case (dashboard, search index, report, notification).
Projections are disposable: delete the checkpoint, restart, and the read model rebuilds from scratch.
See: Projections
Read model
A denormalized data structure optimized for a specific query pattern. Built by a projection from the event stream. Also called a "view" or "query model."
See: Read Models
Snapshot
A saved copy of an aggregate's state at a particular version. Instead of replaying thousands of events from the beginning, the aggregate restores the snapshot and replays only the events after it. An optimization, not a requirement.
State
The current truth derived from events. State is rebuilt by folding events through handlers: state = events.Aggregate(initial, (s, e) => Apply(s, e)). State should contain only what command handlers need to make decisions.
Stream
The sequence of events belonging to one aggregate instance. Each aggregate has its own stream, identified by its aggregate ID.
Subscription
A background process that reads events from the store and delivers them to a handler (projection, notification sender, external API call). Subscriptions track their progress via checkpoints.
See: Projections — Custom subscriptions
Then DSL
The fluent API for expressing command handler decisions:
Then.Persist(event)— accept and recordThen.PersistAll(events)— accept and record multipleThen.Reject("reason")— refuse with explanationThen.Accept()— acknowledge without persisting (idempotent)
See: Aggregates — The Then DSL
Version
The number of events in a single aggregate's stream. Version 0 means no events (new aggregate). Version 5 means five events have been appended. Used for optimistic concurrency checks.
Next: Aggregates