# Aggregate Design Canvas: a worksheet for choosing consistency boundaries

> The Aggregate Design Canvas is a printable modelling sheet for deciding where a domain object ends and another begins, and it pushes you to state invariants, corrective policies, commands, events and expected concurrency conflicts on one page. It is a document rather than a tool, it carries a CC-BY-SA-4.0 licence, and its value is in forcing a conversation rather than in automating one.

**ddd-crew/aggregate-design-canvas** — A structured approach to designing and documenting Aggregates

- Repository: https://github.com/ddd-crew/aggregate-design-canvas
- Stars: 823 · Forks: 77
- Language: Unknown
- License: CC-BY-SA-4.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/ddd-crew-aggregate-design-canvas

## A worksheet for the boundary, not a tool

The Aggregate Design Canvas is described as a modelling tool meant to be used as part of design level domain modelling activities. That phrasing is precise and worth keeping in mind, because it is a sheet, not a program.

What it is for is the hardest conversation in domain driven design: where does one aggregate end and the next begin. The README grounds the concept in Eric Evans' original description of an aggregate as a graph of objects that is a consistency boundary for domain policies. The argument then follows directly. Depending on how you design the aggregate, you either enforce the policies, making them invariants, or you are forced to put corrective policies in place. Because of that, designing the boundaries well matters, since they impact the behaviours modelled within the domain.

The canvas has a suggested order of working through it, and the order is the argument. You start with a name, move to a description, then state transitions, then invariants and corrective policies, then commands and events, then throughput and finally size. Each step feeds the next, and the ordering is designed to make a team iterate over different aspects of the aggregate design rather than settle on a shape in the first ten minutes.

The repository is small and the top level entries say what it contains. There is a README, a CHANGELOG.md, a LICENSE.md, an examples directory with a single file, a naive-bank-account.jpg, a resources directory holding the canvas artwork, and a translations directory. There is no code, no package manifest, and no build.

That is the appeal and the limit in one sentence. The canvas is a printable form that a team fills in by hand or in a whiteboard tool, and it works because it forces structure on a conversation that usually happens in the air.

## Nine sections, in the order the reasoning should happen

The nine sections are the substance of the project, and each one carries a diagnostic hint about what a wrong answer looks like.

Section one is Name. Give your aggregate a good name, and in some domains it makes sense to include the length of a cycle or some other indication of the life span of the aggregate in the name. Section two is Description, where you summarise the main responsibilities and purpose, and the README recommends including the reasons why such boundaries were chosen and the tradeoffs made compared to other designs.

Section three is State Transitions. Usually the aggregate goes through explicit state transitions that affect the way it can be interacted with. Then come the two diagnostic sections, Enforced Invariants and Corrective Policies, described together because they are two sides of the same decision.

Section six and seven are Handled Commands and Created Events, where you list everything the aggregate can handle and everything it will emit as a result, with a suggestion to draw connectors between them so you can check that no building block is missing.

Section eight is Throughput and section nine is Size, and those two are the quantitative part of the sheet. They are also the part most teams skip, which is a shame, because they are the sections that turn a boundary decision into something you can argue about with numbers.

The canvas artwork itself is distributed in several formats, and the download list in the README names the files explicitly:

```
- [Aggregate Design Canvas v1.1 (png)](resources/aggregate-design-canvas-v1.1.png "Aggregate Design Canvas v1.1 (png)")
- [Aggregate Design Canvas v1.1 (pdf)](resources/aggregate-design-canvas-v1.1.pdf "Aggregate Design Canvas v1.1 (pdf)")
- [Aggregate Design Canvas v1.1 (drawio svg)](resources/aggregate-design-canvas-v1.1.drawio.svg "Aggregate Design Canvas v1.1 (drawio svg)")
- [Aggregate Design Canvas v1.1 (Excalidraw)](resources/aggregate-design-canvas-v1.1.excalidraw "Aggregate Design Canvas v1.1 (Excalidraw)")
```

There is also a Brazilian Portuguese translation of the README available. The drawio and Excalidraw versions matter practically, because they let a team edit the canvas rather than print it, and the miro backup lets you take it into a session.

## Invariants versus corrective policies is the real decision

The most valuable pair of sections on the canvas is the one most people skip, and the README is unusually explicit about how to read the numbers you write in them.

One of the main jobs of the aggregate is to enforce business invariants, and these invariants protect business logic. Listing the main ones makes sure the team agrees on the responsibilities the aggregate has. And the README gives you the warning sign: a large number of enforced invariants can indicate high local complexity of the aggregate implementation.

Corrective policies are the mirror image. If you decide to change the boundaries of the aggregate and relax some of the invariants, for example to reduce the chance of a concurrency conflict, then some extra business logic may be required to correct some of the inconsistencies. A large number of such policies might indicate that the business logic was pushed outside the aggregate, which can increase the complexity of implementation.

Read together, the two sections are a diagnostic instrument. Lots of invariants and few corrective policies means the boundary is doing the work and the implementation is locally complex. Few invariants and many corrective policies means the logic has leaked out into services and the aggregate is an anaemic shell. The middle, where both lists are modest, is where the design is probably right.

The README makes the point about listing both explicitly: it will make design trade-offs explicit and help you decide whether the boundaries you decided on are useful or not. That is the mechanism of the tool. It does not decide for you, it makes the consequences of your decision visible on one sheet, which is a different and more achievable goal.

## Throughput and size turn the boundary debate into numbers

The last two sections are where the canvas stops being a checklist and starts being an argument you can settle.

The Throughput section estimates how likely a single aggregate instance is to be involved in concurrency conflicts, which happens when two or more competing callers try to make changes at the same time. There are two metrics. The Command handling rate describes the rate at which the aggregate processes new commands, and the Total number of clients says how many clients are likely to issue those commands. For each metric you estimate the average and the maximum, because the outliers often drive the boundary reevaluation.

The example in the documentation makes it concrete. If an aggregate models a basket on the website, it is likely there is only one client issuing commands to that basket. If you compare that with an aggregate modelling a conference booking system, you are likely to have tens or hundreds of clients trying to book tickets. Two completely different concurrency profiles for the same kind of object, and the profile is a property of the domain, not of the code.

The README supplies a chart for plotting the metrics and states the conclusion it supports: plotting both average and maximum for multiple alternatives lets you explicitly talk about the throughput tradeoffs. Aiming for a small chance of conflict delivers better customer experience but increases implementation complexity, and put the other way, bigger aggregates have a higher chance of a concurrency conflict but fewer policies to correct data. That is a genuine trade-off curve rather than a rule, and the chart is how you locate your design on it.

The Size section estimates the hypothetical size of the aggregate, measured in the number of events per aggregate instance. The caveat is that depending on how you model the domain, the events may be fine or coarse grained, so the size of the events plays a role as well. An OrderCreated event could have multiple LineItems as part of the event, or you could model these line items as separate LineItemAdded events, and in the coarse grained case the overall size of the aggregate is bigger even if the number of events is small.

The metrics here are the Event growth rate, which estimates how many events are appended to a single aggregate instance, and the Lifetime of an instance, which tells you how long the instance will live and therefore how many events will be accumulated and fetched when a new command is processed. A long-lived, high-growth instance is an aggregate that will get slow, and that is a fact you want on the sheet before you commit to the boundary.

## The state transitions section is a smell test in both directions

The state transitions step is short in the documentation and carries a two-sided warning that is worth more than the rest of the section.

The warning about too many transitions is that they might indicate that process boundaries were not modelled properly and can be split. The warning about naive, simple transitions is that they might indicate that the aggregate is anaemic and that logic was pushed out to services.

Both failure modes are common and both are invisible in code review. An aggregate with a dozen states is often several aggregates wearing a trench coat, and the symptom is a state machine that nobody can hold in their head. An aggregate with two states and a lot of behaviour in an application service is the reverse problem, and the symptom is a domain object that is a data bag with methods that do not protect anything.

The instruction is to list the possible states or draw a small transition diagram, which keeps the artefact small enough that the shape of the machine is visible. A drawn diagram is the better option for the pathological case, because a list hides the branches and a diagram makes a dozen states look like a dozen states.

The examples directory contains a single file, a naive bank account example, which is a good sign about the intent. A naive aggregate is exactly the thing this tool exists to catch, and shipping a worked example of one alongside the sheet is more useful than a worked example of a perfect aggregate would be.

There is a genuine gap here, and the documentation is honest about it by omission. The canvas assumes a single aggregate per sheet, and it does not tell you how to decide which aggregate to start with when you have a whole bounded context in front of you. The name, description and state transition steps are where you discover that, and the iterative framing of the canvas is what makes redrawing the boundary cheap.

## What this is not, and how it compares to the alternatives

It is worth being clear that the canvas does not generate code, does not run tests and does not enforce anything. It is a design artefact.

The main alternative is not another tool but another habit, and that is the thing you are really choosing against. Modelling boundaries in a design document, in a wiki page, or in a chat thread all work, and all of them fail in the same way, which is that the conversation converges on a shape nobody argued for because the first plausible sketch became the answer. The canvas is a forcing function. Its nine numbered sections mean the team has to reach the throughput numbers and the event counts, and it puts invariants next to corrective policies so the cost of a relaxed boundary is visible in the same column.

A second alternative is event storming, which is a better tool for finding the domain and the processes, and a worse one for settling a specific boundary once you have candidates. The two are complementary rather than competing, and the canvas would sit naturally at the end of an event storming session, with the states and commands already on the wall.

A third is a lightweight event sourced implementation, where you decide the boundary by making it and seeing whether the stream works. That approach produces working software faster and produces a worse model, and it is a reasonable trade for a prototype and a poor one for a core domain you have to maintain for years.

The trade with the canvas is that it costs a meeting and produces no code. For a system where the aggregate boundaries are the central architectural decision, that meeting is cheap. For a system where the boundaries are obvious and the interesting work is elsewhere, it is a wasted afternoon.

## Licence, translation and the state of the project

The licence is CC-BY-SA-4.0, which is a content licence rather than a software licence, and that is the correct choice for a worksheet. It lets a team use the canvas in internal documentation, adapt it, and redistribute a filled copy, provided attribution is given. The share-alike condition applies to adaptations of the canvas itself, so if you redesign the layout you are expected to publish that redesign under the same terms. For a document that is meant to be copied, printed and marked up, that is a sensible balance.

One thing to check if you plan to publish filled canvases outside your organisation: the share-alike terms can reach the document that embeds the adapted canvas, and that is a different question from the licence on the blank form.

There is a Brazilian Portuguese translation of the README in the translations directory, which is a small but real signal about the audience. The README also points to the docs website and asks people to help translate, so the project is actively looking for more languages.

On maintenance, the repository is not archived and the last push was on 2026-08-23. There are no GitHub releases, and the version is tracked in the canvas filenames and the CHANGELOG rather than in tags, with v1.1 the current artwork and v1 the earlier one. A document project moves slowly by nature, so a two month gap between pushes is not a concern in the way it would be for a library.

The CHANGELOG in the repository root is where the version history lives, and the resources directory holds the artwork for both versions in every format, so the practical upgrade path is straightforward: download the newer canvas, open it in the tool your team already uses, and carry the sections forward.

## Conclusion

Adopt the Aggregate Design Canvas if your team is designing domain boundaries and arguing about them in prose, because the sheet converts a vague discussion into nine named sections with explicit tradeoffs. Do not adopt it as a substitute for the modelling itself, since the canvas records decisions rather than making them, and do not expect it to tell you what the right boundary is. Verify first that the team will actually fill in the throughput and size sections, because a canvas with those left blank documents intent rather than risk, and check the CC-BY-SA-4.0 terms before you redistribute a filled copy outside your organisation.

## FAQ

### What is the Aggregate Design Canvas?

It is a modelling tool for design level domain modelling that helps teams decide aggregate boundaries, which are consistency boundaries for domain policies. It has a suggested order of working through nine sections covering name, description, state transitions, invariants, corrective policies, commands, events, throughput and size.

### What is the difference between enforced invariants and corrective policies?

Enforced invariants are business rules the aggregate itself protects. Corrective policies are the extra logic needed when you relax those invariants, for example to reduce concurrency conflicts. The README notes that many invariants indicate high local complexity, while many corrective policies suggest the business logic was pushed outside the aggregate.

### In what formats is the Aggregate Design Canvas available?

For version 1.1 the resources directory holds a png, a pdf, a miro board backup, a drawio svg and an Excalidraw file, and version 1 is also available as a jpg, a pdf, a miro backup and a drawio svg. The drawio and Excalidraw versions let a team edit the canvas rather than print it.

### What does the throughput section of the Aggregate Design Canvas measure?

It estimates how likely a single aggregate instance is to hit concurrency conflicts when competing callers change it at the same time. You record the command handling rate and the total number of clients, each as an average and a maximum, and plot them on the concurrency conflict chance chart to compare alternative designs.

### What license does the Aggregate Design Canvas use?

CC-BY-SA-4.0, recorded in the repository as LICENSE.md. It is a content licence, so teams can copy, fill in and redistribute the canvas with attribution, and adaptations carry the same share-alike terms.

## Sources

- [ddd-crew/aggregate-design-canvas on GitHub](https://github.com/ddd-crew/aggregate-design-canvas)
- [Issues](https://github.com/ddd-crew/aggregate-design-canvas/issues)
- [License: CC-BY-SA-4.0](https://github.com/ddd-crew/aggregate-design-canvas/blob/main/LICENSE)
- [README](https://github.com/ddd-crew/aggregate-design-canvas/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ddd-crew-aggregate-design-canvas
