Skip to content

Dynamic Consistency Boundary (DCB)

Why DCB exists and how it actually works

Streams are great for per-aggregate consistency. They fall apart when a rule spans multiple streams:

  • unique usernames across all users
  • no double-booking across all rooms
  • invoice numbers that never collide

Traditional event sourcing pushes those into sagas and compensations. DCB keeps the rule in one place by letting you check a query, not a stream.

DCB has three moving parts:

  1. Tags on events (opaque strings like username:alice)
  2. Query that matches events by type and/or tags
  3. Append condition that fails if any matching events appear after a position you already saw

The flow looks like this:

readByQuery(query) -> events + lastPosition
decide(events) -> new event
append(events, { failIfEventsMatch: query, after: lastPosition })

If someone else writes a conflicting event in between, your append fails. No saga. No compensation.

DeltaBase keeps the stream API intact and adds a streamless DCB API.

  • Stream path: readStream() + appendToStream()
  • Atomic multi-stream path: multiStreamAppend()
  • DCB path: readByQuery() + append()

Both can coexist. Use DCB only where you need cross-stream guarantees.

multiStreamAppend() is different from DCB.

It is a transaction across known streams:

await eventStore.multiStreamAppend([
{
streamId: 'order-123',
events: [{ type: 'order.created', data: { orderId: '123' } }],
expectedStreamVersion: 'no_stream',
},
{
streamId: 'customer-456',
events: [{ type: 'customer.orderAdded', data: { orderId: '123' } }],
expectedStreamVersion: 7,
},
]);

All stream version checks pass and all events are written, or nothing is written. That’s useful when one command changes several aggregates and you already know exactly which streams are involved.

DCB is a condition over a query. You use it when the rule is not tied to one known stream list, like “no user can claim this username after the position I just read.”

Use DCB when:

  • the rule spans multiple streams
  • you need global uniqueness or limits
  • you want one event to affect multiple entities

Use streams when:

  • the rule is per aggregate
  • your invariants live inside one stream
  • you care about per-stream ordering and versioning

Use multi-stream append when:

  • one command writes several known streams
  • partial success would be wrong
  • per-stream expected versions express the consistency rule
  • It is not a database transaction across aggregates
  • It does not prevent all races, only the ones you model in the query
  • It does not replace streams for aggregate-level logic

DCB is a targeted tool. Use it where it matters.