Views
The master model is authored; views are declared as selections over it,
and the common ones need zero declaration at all — an empty or absent
views block gets the zero-config default set.
The induced-subgraph rule
A view is fundamentally a set of elements, however that set is produced.
Given the set, every model relationship whose two endpoints are both in the
set is included automatically, and ancestors of included elements are pulled
in as boundary boxes for rendering context. This is why a hand-written
include a b c never has to enumerate relationships — the system derives
the edges.
Selectors
One expression language, used by include/exclude, generator arguments,
and structurizrx query:
element.tag==Database
element.kind==container
element.status==idea
element.layer==domain // layer = group name, or the `layer` property
element.parent==shop // direct children
element.technology==Kafka
element.property.owner==checkout-team
relationship.kind==async
relationship.tag==critical
->api-> // neighborhood: api + direct neighbors
a && b, a || b, !a // boolean combinators
Two properties get special tooling awareness beyond the generic
element.property.<name> lookup: owner (default rollup partition, a
digest column, and an optional unowned-element lint) and layer (layer
views, layer-order lint). They’re still stored as ordinary properties.
Selectors filter; they can’t compute anything requiring a graph walk — that’s what generators are for.
The auto generator family
Each generator answers a specific stakeholder question. All of them can
appear any number of times in a views block, and generated views get
deterministic keys (auto-focus-api, auto-context-shop) so links and
stored layout survive regeneration.
views {
auto // zoom ladder: landscape + context per system + container
// view per non-empty system + component view per
// non-empty container. Zero-config default when the
// `views` block is absent or just says `auto`.
}
“What breaks if I change X? What does X need?” — reachability:
auto focus api {
depth 2 // default 1; unset = 1
direction in // in = impact analysis (who depends on me)
// out = dependency analysis (what do I need)
// both (default when direction is omitted)
splitBy kind // one *separate view* per relationship kind present
}
Without splitBy, focus emits a single combined view.
“How are X and Y connected at all?” — path enumeration:
auto paths web db // all simple paths web → db
“Where does concern C live?” — cross-cutting slices:
auto perspective "security" // everything carrying that perspective
auto layer "domain"
auto slice relationship.kind==dataflow
auto slice element.status==idea
layer groups elements for this kind of slicing; see
layers.dsl
for a worked example that groups a system into "Core" and "Data" and
generates one auto layer view per group.
“What’s unfinished or inconsistent?” — model hygiene:
auto lint // placeholder elements, ?-marked items, unbound ports,
// orphan elements
“What changes between now and milestone M?” — temporal, keyed off
milestones:
auto asof billingSplit // model state at that milestone;
// `asof now` filters out everything future
auto delta now billingSplit // union of both states — a migration/diff view
Not yet materialized:
auto rollup(the partition/Conway-view generator described indocs/SPEC.md§6.3) parses successfully but currently emits nothing —generate_viewsaccepts the syntax and prints a note that it was skipped, rather than producing a view. Likewise thecollapsemodifier for folding n-ary connectors isn’t implemented yet. Check the repository README’s Status section for the current gap list before relying on either.
Dynamic and deployment views
Dynamic views (ordered interaction scenarios) and deployment views exist and parse using standard upstream Structurizr syntax, unchanged.
A dynamic view numbers a sequence of source -> destination "description"
steps in the order they’re declared, for answering “what happens, in what
order, when this use case runs”:
dynamic shop "checkout" "Placing an order" {
customer -> web "Clicks 'Buy now'"
web -> api "POST /orders"
api -> db "Inserts order row"
autoLayout
}
A deployment view selects from a deploymentEnvironment — the
infrastructure a system runs on (deploymentNode, containerInstance,
infrastructureNode) — rather than from the model’s structure:
production = deploymentEnvironment "Production" {
deploymentNode "Amazon Web Services" {
deploymentNode "EC2 instance" {
apiInstance = containerInstance api
}
}
}
views {
deployment shop "Production" { include * }
}
Full runnable examples:
checkout-flow.dsl
and
deployment.dsl.
Not yet rendered: both view types validate and digest correctly, but none of the four exporters (SVG, Mermaid, PlantUML, DOT) draws them yet —
rendersilently skips them with a warning today. The container view below is the same underlying model, shown via a view type that does render, as a stand-in until dynamic/deployment rendering lands.
Next: Documentation and decisions for !adrs/!include.