Skip to content

Projections

Your events are the source of truth, but events are a poor thing to read — nobody wants to replay a thousand MoneyDeposited facts to show an account balance. A projection does that folding for you: it watches a stream of events and continuously builds a read model — a shaped, queryable view that’s ready to serve to a UI.

The win is specialization. The same events can feed many projections, each tailored to one screen or question: a balance, a transaction list, a monthly summary. You never reuse one bloated model across conflicting needs — you build a focused read model per view, and each stays simple, fast, and independent.

maps & merges

Event

Projection

Event

Event

Read model

Query

Projections join events (never other read models), and mapping is automatic by default — name a read model property the same as an event property and it just maps. For a read model backed by events, you usually choose between three styles:

StyleWhat it looks likeReach for it when
Model-boundAttributes on the read model record ([FromEvent<T>], [Key], [ChildrenFrom<T>])The default. Most projections — it’s the least boilerplate and reads as the model itself.
DeclarativeA fluent IProjectionFor<T> definitionThe mapping needs logic the attributes can’t express cleanly.
ReducerAn IReducerFor<T> that receives the event, current state, and event contextThe read model is easier to express as state transitions or calculations over previous state.

Choose a read-model style builds the same read model as a model-bound projection, a declarative projection, and a reducer so the trade-offs are visible side by side.

The one decision worth making up front is when the read model has to be correct:

EventualImmediate
When it updatesShortly after the event is appended (the default)Synchronously, before the append returns
CostCheap, scales freelyMore expensive — pay only when you need it
Use it forAlmost everything — lists, dashboards, historyA value you must read back correctly right now (e.g. a uniqueness check)

Start eventual. Promote a projection to immediate only when a workflow genuinely can’t tolerate the read model being a moment behind.

TopicDescription
ArchitectureHow the projection engine turns events into read models
Choose a read-model styleCompare model-bound, declarative, and reducer approaches on the same read model
Model-Bound ProjectionsBuild read models with attributes — the default style
Declarative ProjectionsBuild read models with the fluent IProjectionFor<T> API
Immediate ProjectionsStrong consistency — the read model updates before the append returns
Eventual ConsistencyThe default — how and when eventual projections catch up
Tagging ProjectionsOrganize and tag projections
Appended event metadata filtersHow tags and metadata correlate reducers and reactors that run alongside projections

Once your read model exists, expose it to the frontend with a query — or see the whole loop in Build a full-stack feature.