Concepts

Dynamic Consistency Boundary (DCB)

Traditional event-sourced systems force a hard choice early. You define your aggregates up front, and those boundaries stay fixed for the life of the system. When a business rule later needs to span more than one aggregate, teams reach for process managers, sagas with compensating actions, and other coordination patterns that add complexity and slow every future change.

Dynamic Consistency Boundary (DCB) removes that constraint. It lets an application define the scope of transactional consistency for each operation at the moment the operation runs, rather than locking it into the shape of the data model. The result is an event-sourced architecture that can evolve with the business without discarding event history or rebuilding what already works.

Fixed at design time

A stream holds one aggregate. A fact about a student and a course has to be appended to both streams, once for each.

STUDENT AGGREGATE
StudentEnrolledInFaculty
COURSE AGGREGATE
CourseCreated
CourseCapacityChanged
CONCERNS BOTH · EVENTS APPENDED TO BOTH STREAMS
StudentSubscribedToCourse
StudentUnsubscribedFromCourse
The same fact is stored twice, in two separate appends. Each box enforces only its own rule, never both at once, so the gap is closed by compensation.
VS

Defined per operation

The boundary is a set of events selected by a tag. An event with two tags is in two boundaries at once.

boundary · tag = student:s-13 events
StudentEnrolledInFaculty
student:s-1
CourseCreated
course:c-9
StudentSubscribedToCourseIN BOTH
student:s-1course:c-9
CourseCapacityChanged
course:c-9
StudentUnsubscribedFromCourseIN BOTH
student:s-1course:c-9
Stored once, tagged twice. No duplicate events, and each rule reads exactly what it needs.

Fixed at design time

A stream holds one aggregate. A fact about a student and a course has to be appended to both streams, once for each.

STUDENT AGGREGATE
StudentEnrolledInFaculty
COURSE AGGREGATE
CourseCreated
CourseCapacityChanged
CONCERNS BOTH · EVENTS APPENDED TO BOTH STREAMS
StudentSubscribedToCourse
StudentUnsubscribedFromCourse
The same fact is stored twice, in two separate appends. Each box enforces only its own rule, never both at once, so the gap is closed by compensation.
VS

Defined per operation

The boundary is a set of events selected by a tag. An event with two tags is in two boundaries at once.

boundary · tag = student:s-13 events
StudentEnrolledInFaculty
student:s-1
CourseCreated
course:c-9
StudentSubscribedToCourseIN BOTH
student:s-1course:c-9
CourseCapacityChanged
course:c-9
StudentUnsubscribedFromCourseIN BOTH
student:s-1course:c-9
Stored once, tagged twice. No duplicate events, and each rule reads exactly what it needs.

Fixed at design time

A stream holds one aggregate. A fact about a student and a course has to be appended to both streams, once for each.

STUDENT AGGREGATE
StudentEnrolledInFaculty
COURSE AGGREGATE
CourseCreated
CourseCapacityChanged
CONCERNS BOTH · EVENTS APPENDED TO BOTH STREAMS
StudentSubscribedToCourse
StudentUnsubscribedFromCourse
The same fact is stored twice, in two separate appends. Each box enforces only its own rule, never both at once, so the gap is closed by compensation.
VS

Defined per operation

The boundary is a set of events selected by a tag. An event with two tags is in two boundaries at once.

boundary · tag = student:s-13 events
StudentEnrolledInFaculty
student:s-1
CourseCreated
course:c-9
StudentSubscribedToCourseIN BOTH
student:s-1course:c-9
CourseCapacityChanged
course:c-9
StudentUnsubscribedFromCourseIN BOTH
student:s-1course:c-9
Stored once, tagged twice. No duplicate events, and each rule reads exactly what it needs.

Sara Pellegrini and Milan Savic introduced the Dynamic Consistency Boundary concept in 2024. Axoniq implemented it in Axon Server and Axon Framework 5 (AF5). It shifts event-sourced applications from consistency boundaries fixed at design time to boundaries defined dynamically for each operation.

What is a Dynamic Consistency Boundary (DCB)?

A Dynamic Consistency Boundary (DCB) is an architectural model for event-sourced systems that defines the scope of transactional consistency dynamically for each operation, rather than binding it to a fixed aggregate. Each event is tagged with one or more values when it is written. A typical tag value would be an identifier. When an operation needs to enforce a business rule, the application retrieves only the events associated with the relevant tags, constructs an in-memory model from that history, validates the rule, and atomically appends the resulting event.

The boundary exists only for the lifetime of that operation. It forms a temporary consistency scope around exactly the data required to evaluate the business rule, then disappears once the write completes. Because boundaries are defined by event tags rather than static object hierarchies, the same event can participate in multiple consistency boundaries without duplication.

What is the benefit of a Dynamic Consistency Boundary?

The core benefit is agility without sacrificing correctness, reducing the cost of change as business requirements evolve. Business rules that span multiple domain concepts can be enforced within a single atomic operation, reducing the need for coordination patterns like sagas when consistency is required immediately. When requirements change, teams can redefine the consistency boundary for an operation rather than restructuring aggregates, migrating data, or rewriting event history. This allows event-sourced systems to adapt to new business needs faster while preserving their existing history and avoiding costly redesigns.

Why do traditional aggregate boundaries create problems?

In classic event sourcing, an aggregate is the unit of consistency. Every rule that must hold true atomically has to live inside a single aggregate, and every event belongs to exactly one aggregate [or the event belongs to none]. That works cleanly until a rule needs to consider data that lives in more than one place.

Consider a lending example. A bank must ensure that approving a loan application respects multiple business rules at the same time: the customer's existing exposure, their current credit limit, and the institution's lending policy. If the customer profile, existing loans, and credit limits are modeled as separate aggregates, no single aggregate can enforce all of those rules in one transaction. Teams then introduce coordination logic to synchronize decisions across aggregates, along with compensating actions when part of the process fails. What should have been one business decision becomes a distributed process that is harder to reason about, test, and audit.

StudentAGGREGATE
StudentEnrolled
courses: 2 / 10
Saga

awaiting steps

CourseAGGREGATE
SeatReserved
capacity: 30 / 30
Command arrives: enrol student in course
StudentAGGREGATE
StudentEnrolled
courses: 2 / 10
Saga

awaiting steps

CourseAGGREGATE
SeatReserved
capacity: 30 / 30
Command arrives: enrol student in course
StudentAGGREGATE
StudentEnrolled
courses: 2 / 10
Saga

awaiting steps

CourseAGGREGATE
SeatReserved
capacity: 30 / 30
Command arrives: enrol student in course

The same pattern shows up in eCommerce. A customer placing an order may trigger rules across multiple parts of the system: inventory availability, pricing eligibility, promotions, and customer purchase limits. If inventory, pricing, and customer accounts are modeled as separate aggregates, no single aggregate can enforce all of those rules in one transaction.

The deeper problem is that these boundaries are chosen up front. Once aggregates are defined, changing them usually requires data migration, event transformation, and downtime, because the structure of the stored data is tied to the original decision.

How does a Dynamic Consistency Boundary work?

DCB replaces the fixed aggregate boundary with a boundary defined by tags and queried per operation. It works in four steps.

First, events are tagged at publication. Each event carries zero or more tags that describe the entities it relates to, such as a student identifier and a course identifier on a single enrollment event.

Second, the operation queries events by tag. Instead of loading a whole aggregate, the operation selects exactly the events it needs using criteria over those tags. Axon Server (the event store) returns the matching events as an ordered list, and after the last event it returns a consistency marker, a position representing "everything matching this query, up to here."

Third, the application builds a temporary model and enforces the rules. The events returned by the query are folded into a small in-memory model that holds just enough state to check the business rules for this operation, for example, how many courses the student already holds and whether the course is full.

Fourth, the event is appended atomically with a consistency check. The append call includes the consistency marker from step two, the position the decision was actually based on. Axon Server checks whether any new events matching the same tag criteria have been written since that marker. If so, the write is rejected, which stops two concurrent operations from breaking the rule. The operation gets atomic consistency across everything the boundary covers.

01Tag at publication

Every event carries a tag for each entity it relates to.

02Query by tag

One criteria item per entity, combined with OR. The matches are the boundary.

03Fold a decision model

Just enough in-memory state to check the rules, then thrown away.

04Append with a condition

The write carries the same query plus the last position read.

EVENT STORE · AXON SERVER4 IN BOUNDARY
41StudentEnrolledInFaculty
student:s-1
42CourseCreated
course:c-9
43StudentEnrolledInFaculty
student:s-2
44StudentSubscribedToCourse
student:s-2course:c-9
45CourseCapacityChanged
course:c-4
46StudentSubscribedToCourse
student:s-1course:c-4
47StudentSubscribedToCourse
student:s-1course:c-9
DECIDING ON: SUBSCRIBE s-1 TO c-9
QUERY
tags = course:c-9
OR
tags = student:s-1
DECISION MODEL · FOLDED FROM 4 EVENTS
course existsyes
seats taken1 / 30
student subscriptions1 / 5
rules not yet evaluated
APPEND CONDITION
failIfEventsMatch: the same query
after: position 46
checked at write time, not at read time
01Tag at publication

Every event carries a tag for each entity it relates to.

02Query by tag

One criteria item per entity, combined with OR. The matches are the boundary.

03Fold a decision model

Just enough in-memory state to check the rules, then thrown away.

04Append with a condition

The write carries the same query plus the last position read.

EVENT STORE · AXON SERVER4 IN BOUNDARY
41StudentEnrolledInFaculty
student:s-1
42CourseCreated
course:c-9
43StudentEnrolledInFaculty
student:s-2
44StudentSubscribedToCourse
student:s-2course:c-9
45CourseCapacityChanged
course:c-4
46StudentSubscribedToCourse
student:s-1course:c-4
47StudentSubscribedToCourse
student:s-1course:c-9
DECIDING ON: SUBSCRIBE s-1 TO c-9
QUERY
tags = course:c-9
OR
tags = student:s-1
DECISION MODEL · FOLDED FROM 4 EVENTS
course existsyes
seats taken1 / 30
student subscriptions1 / 5
rules not yet evaluated
APPEND CONDITION
failIfEventsMatch: the same query
after: position 46
checked at write time, not at read time
01Tag at publication

Every event carries a tag for each entity it relates to.

02Query by tag

One criteria item per entity, combined with OR. The matches are the boundary.

03Fold a decision model

Just enough in-memory state to check the rules, then thrown away.

04Append with a condition

The write carries the same query plus the last position read.

EVENT STORE · AXON SERVER4 IN BOUNDARY
41StudentEnrolledInFaculty
student:s-1
42CourseCreated
course:c-9
43StudentEnrolledInFaculty
student:s-2
44StudentSubscribedToCourse
student:s-2course:c-9
45CourseCapacityChanged
course:c-4
46StudentSubscribedToCourse
student:s-1course:c-4
47StudentSubscribedToCourse
student:s-1course:c-9
DECIDING ON: SUBSCRIBE s-1 TO c-9
QUERY
tags = course:c-9
OR
tags = student:s-1
DECISION MODEL · FOLDED FROM 4 EVENTS
course existsyes
seats taken1 / 30
student subscriptions1 / 5
rules not yet evaluated
APPEND CONDITION
failIfEventsMatch: the same query
after: position 46
checked at write time, not at read time

Because each event can carry several tags, a single enrollment event can belong to the student boundary and the course boundary at once. There is one event, stored once, taking part in as many boundaries as its tags allow.

How is DCB different from process managers and sagas?

A saga coordinates a business rule across several aggregates by running a sequence of steps and issuing compensating actions when a step fails. It accepts that the system passes through temporary inconsistent states and adds logic to correct them. That logic grows with every rule and becomes a major source of complexity in distributed systems.

A Dynamic Consistency Boundary enforces the same domain concepts rule inside one atomic operation. The operation reads the tagged events it needs, validates the rule, and writes the result as a single append that either succeeds completely or fails completely. There is no partial state to compensate for, so the compensating logic disappears along with the saga.

The saga pattern remains useful for long-running processes that genuinely span time, services, and bounded contexts. They are no longer required simply because a rule happens to touch more than one entity.

How is DCB different from a traditional aggregate boundary?

A traditional aggregate boundary is fixed at design time and defined by structure. Every event belongs to at most one aggregate, the association is optional, not every event needs one — and every atomic rule must fit inside that single aggregate. A Dynamic Consistency Boundary is defined at run time and expressed through tags. An event can belong to many boundaries, and each operation decides which events matter to it.

FIXED AT DESIGN TIME
Aggregate boundary

Defined by structure. Every event belongs to at most one aggregate.

STUDENT
StudentEnrolledInFaculty
COURSE
CourseCreated
CourseCapacityChanged
CONCERNS BOTH · EVENTS APPENDED TO BOTH STREAMS
StudentSubscribedToCourse
The same fact is appended twice. Each box enforces only its own rule, so capacity and the student's limit together need coordination outside them.
DEFINED AT RUN TIME
Dynamic Consistency Boundary

Expressed through tags. One stored event takes part in every boundary its tags allow, with no duplicates.

tags = student:s-1Everything one student did.
StudentEnrolledInFaculty
student:s-1
CourseCreated
course:c-9
StudentSubscribedToCourse
student:s-1course:c-9
CourseCapacityChanged
course:c-9
StudentSubscribedToCourse
student:s-2course:c-9
Items combine with OR, tags inside one item combine with AND.
FIXED AT DESIGN TIME
Aggregate boundary

Defined by structure. Every event belongs to at most one aggregate.

STUDENT
StudentEnrolledInFaculty
COURSE
CourseCreated
CourseCapacityChanged
CONCERNS BOTH · EVENTS APPENDED TO BOTH STREAMS
StudentSubscribedToCourse
The same fact is appended twice. Each box enforces only its own rule, so capacity and the student's limit together need coordination outside them.
DEFINED AT RUN TIME
Dynamic Consistency Boundary

Expressed through tags. One stored event takes part in every boundary its tags allow, with no duplicates.

tags = student:s-1Everything one student did.
StudentEnrolledInFaculty
student:s-1
CourseCreated
course:c-9
StudentSubscribedToCourse
student:s-1course:c-9
CourseCapacityChanged
course:c-9
StudentSubscribedToCourse
student:s-2course:c-9
Items combine with OR, tags inside one item combine with AND.
FIXED AT DESIGN TIME
Aggregate boundary

Defined by structure. Every event belongs to at most one aggregate.

STUDENT
StudentEnrolledInFaculty
COURSE
CourseCreated
CourseCapacityChanged
CONCERNS BOTH · EVENTS APPENDED TO BOTH STREAMS
StudentSubscribedToCourse
The same fact is appended twice. Each box enforces only its own rule, so capacity and the student's limit together need coordination outside them.
DEFINED AT RUN TIME
Dynamic Consistency Boundary

Expressed through tags. One stored event takes part in every boundary its tags allow, with no duplicates.

tags = student:s-1Everything one student did.
StudentEnrolledInFaculty
student:s-1
CourseCreated
course:c-9
StudentSubscribedToCourse
student:s-1course:c-9
CourseCapacityChanged
course:c-9
StudentSubscribedToCourse
student:s-2course:c-9
Items combine with OR, tags inside one item combine with AND.

This changes what happens when requirements evolve. With fixed aggregates, a new rule that spans entities forces structural change and often data migration. With DCB, the same new rule is expressed by querying a different set of tags, so the architecture adapts without touching stored history. The event history accumulated since day one stays valid and reusable.

Dynamic Consistency Boundary and Vertical Slice Architecture

DCB pairs naturally with Vertical Slice Architecture, which organizes code around business features rather than technical layers. Because boundaries are defined per operation, each feature slice can read the same underlying events through its own tags and build its own model, independent of the others. A write slice, a read slice, and an automation slice can all draw on the same events while staying decoupled. This lets teams add and change features without coordinating across a shared aggregate structure.

WRITE SLICE+ APPEND CONDITION
Subscribe student to course

Checks capacity and the student's limit, then appends one event under the same query.

CRITERIAtags = course:c-9 OR student:s-1
READ SLICEREAD ONLY
Course roster

Projects who is on the course right now.

CRITERIAtags = course:c-9types =CourseCreatedCourseCapacityChangedStudentSubscribedToCourse
AUTOMATION SLICEREAD ONLY
Course full notifier

Warns the faculty when the last seat goes.

CRITERIAtags = course:c-9types =StudentSubscribedToCourse
ONE SHARED EVENT STREAM
StudentEnrolledInFaculty
student:s-1
CourseCreated
course:c-9
StudentSubscribedToCourse
student:s-1course:c-9
CourseCapacityChanged
course:c-9
StudentSubscribedToCourse
student:s-2course:c-9
Every slice reads the same stream through its own criteria. Only the write slice turns its criteria into an append condition.
WRITE SLICE+ APPEND CONDITION
Subscribe student to course

Checks capacity and the student's limit, then appends one event under the same query.

CRITERIAtags = course:c-9 OR student:s-1
READ SLICEREAD ONLY
Course roster

Projects who is on the course right now.

CRITERIAtags = course:c-9types =CourseCreatedCourseCapacityChangedStudentSubscribedToCourse
AUTOMATION SLICEREAD ONLY
Course full notifier

Warns the faculty when the last seat goes.

CRITERIAtags = course:c-9types =StudentSubscribedToCourse
ONE SHARED EVENT STREAM
StudentEnrolledInFaculty
student:s-1
CourseCreated
course:c-9
StudentSubscribedToCourse
student:s-1course:c-9
CourseCapacityChanged
course:c-9
StudentSubscribedToCourse
student:s-2course:c-9
Every slice reads the same stream through its own criteria. Only the write slice turns its criteria into an append condition.
WRITE SLICE+ APPEND CONDITION
Subscribe student to course

Checks capacity and the student's limit, then appends one event under the same query.

CRITERIAtags = course:c-9 OR student:s-1
READ SLICEREAD ONLY
Course roster

Projects who is on the course right now.

CRITERIAtags = course:c-9types =CourseCreatedCourseCapacityChangedStudentSubscribedToCourse
AUTOMATION SLICEREAD ONLY
Course full notifier

Warns the faculty when the last seat goes.

CRITERIAtags = course:c-9types =StudentSubscribedToCourse
ONE SHARED EVENT STREAM
StudentEnrolledInFaculty
student:s-1
CourseCreated
course:c-9
StudentSubscribedToCourse
student:s-1course:c-9
CourseCapacityChanged
course:c-9
StudentSubscribedToCourse
student:s-2course:c-9
Every slice reads the same stream through its own criteria. Only the write slice turns its criteria into an append condition.

What are the benefits of a Dynamic Consistency Boundary?

DCB delivers several concrete benefits for event-sourced systems.

01

Atomic consistency across domain concepts, without processes and sagas.

02

Architectural change without data migration, because boundaries move by changing tag queries rather than by rewriting history.

03

Can support faster delivery, with new capabilities able to ship in weeks or months instead of quarters.

04

A single source of truth, because each event is stored once and reused across many boundaries.

05

Efficient reads and writes, because operations load only the events a rule needs rather than entire aggregates.

Why DCB matters
for AI and auditability

Regulated industries increasingly need to explain why a system reached a given decision, and that need grows sharply as AI moves into production. Event sourcing already provides this: because every state change is recorded as it happens, the complete sequence of events behind any outcome is preserved by design.

DCB doesn't create this property, it inherits it, without giving up anything to solve the consistency-boundary problem.

What DCB adds is precision: because tags define exactly which events a given operation cared about, reconstructing the specific set of events that informed a decision is straightforward, not just possible in principle. Traceability remains a property of event sourcing; DCB keeps that property intact while making it easier to point to the exact events behind a specific decision, which matters both for audit readiness and for explaining the behavior of AI systems that act on event history.

🤔
Frequently

asked
questions

🤔
Frequently asked

questions

What is a Dynamic Consistency Boundary in simple terms?

It is a way to enforce a business rule across several entities in one atomic operation, by tagging events and querying only the ones the rule needs, instead of locking that rule inside a fixed aggregate.

Who created Dynamic Consistency Boundary?

DCB was originally conceived in 2023 by Sara Pellegrini and Milan Savic, a former and a current collaborator of Axoniq, respectively. In 2024, Axoniq implemented the concept in Axon Framework 5.0, with support for Axon Server 2025.1.0

Does DCB replace event sourcing?

No. DCB is an adjustment to the event store used for event sourcing. It changes how consistency boundaries are defined, while events remain the source of truth.

Does adopting DCB require migrating existing data?

Changing a boundary in a DCB system does not require data migration, because boundaries are defined by tag queries rather than by data structure. Teams should still follow current Axon Server guidance when introducing DCB into an existing deployment.

When should I still use a saga?

Sagas remain appropriate for long-running processes that genuinely span time and multiple services. DCB removes the need for a saga when the only reason for one was enforcing a rule across more than one entity.

Get Started with Axoniq

Bring flexibility to your event-sourced systems

Dynamic Consistency Boundary changes event sourcing from a model where structure is fixed early to one where consistency adapts to each operation. Teams keep the correctness guarantees they rely on and gain the freedom to let the architecture follow the business. For systems that need to evolve continuously and explain themselves clearly, that combination is the point.