Skip to content

Projections, reducers, and reactors

Projections, reducers, and reactors are all observers: they watch an event sequence and run as events arrive. The confusion is that they look similar and are often explained on separate pages. This page puts them side by side so you can pick the right one without second-guessing.

The one-line distinction:

  • Projection and reducer build state (a read model) — declaratively or imperatively.
  • Reactor causes effects (notify, integrate, trigger a command) — it builds nothing.

State you can query

A side effect when something happens

Like data: map and merge events

Needs custom folding logic

What do you need?

How is it shaped?

Reactor

Projection

Reducer

ProjectionReducerReactor
PurposeBuild a read modelBuild a read modelDo a side effect
HowDeclarative ([ReadModel] + model-bound attributes, AutoMap)Imperative fold you writeA method per event type
ProducesA read model instance you queryA value you queryNothing (acts on the outside world)
Reach for it whenThe read side is shaped like dataA projection can’t express the logic cleanlyYou must notify, integrate, or trigger a command
Must be idempotentHandled for you (rebuildable)Handled for you (rebuildable)Yes — you own this

Building state doesn’t have to mean materializing it. Projections and reducers also compute state on demand — Chronicle replays the relevant events through them when you ask, which is how reading a single instance serves strongly consistent results. That makes them useful beyond query views: validation rules, aggregate roots in Arc, or anything else that needs current state it can trust.

  1. Do you want state you can query, or an effect in the outside world?
    • State → projection or reducer.
    • Effect → reactor.
  2. If state: can you express it as “map these event properties onto this model”?
    • Yes → Projection. Start here — it’s the least code and AutoMap does most of the work.
    • No, it needs real logic (running totals, conditional accumulation) → Reducer.
  3. If effect: use a Reactor — and design it to be safe to run more than once, because it will be (replay, recovery, redeploy).
  • A projection/reducer never causes side effects — no emails, no API calls. They only build state.
  • A reactor never builds state and never writes to the event log directly — if it must produce new events, it executes a command through the command pipeline.
  • All of them are rebuildable: because events are the source of truth, you can replay to rebuild a read model at any time.
  • Projections — the full range, including declarative and model-bound styles.
  • Reducers — when and how to fold.
  • Reactors — side effects and idempotency.
  • Read Models — what projections and reducers write to, and how consistency works.