Dynamic Consistency Boundary (DCB)
Why DCB exists and how it actually works
Why DCB exists
Section titled “Why DCB exists”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.
How DCB actually works
Section titled “How DCB actually works”DCB has three moving parts:
- Tags on events (opaque strings like
username:alice) - Query that matches events by type and/or tags
- Append condition that fails if any matching events appear after a position you already saw
The flow looks like this:
readByQuery(query) -> events + lastPositiondecide(events) -> new eventappend(events, { failIfEventsMatch: query, after: lastPosition })If someone else writes a conflicting event in between, your append fails. No saga. No compensation.
DCB in DeltaBase
Section titled “DCB in DeltaBase”DeltaBase keeps the stream API intact and adds a streamless DCB API.
- Stream path:
readStream()+appendToStream() - DCB path:
readByQuery()+append()
Both can coexist. Use DCB only where you need cross-stream guarantees.
When to use DCB vs streams
Section titled “When to use DCB vs streams”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
What DCB is not
Section titled “What DCB is not”- 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.