The Structurizr DSL provides a way to define a software architecture model (based upon the C4 model) as text, using a domain specific language (DSL). The Structurizr CLI (command line interface) provides tooling to parse DSL workspace definitions, upload them to the Structurizr cloud service/on-premises installation, and export diagrams to other formats (e.g. PlantUML and WebSequenceDiagrams). See https://structurizr.com/dsl for a demo of the DSL.
Please note that what you see here may not be available in the Structurizr CLI yet, but it will likely be available on the Structurizr DSL demo page.
- General rules
- String substitution
- Comments
- Identifiers
- !include
- !constant
- !expressions
- Grammar
- Line breaks are important.
- Tokens must be separated by whitespace, but the quantity of whitespace/indentation isn't important.
- Keywords are case-insensitive (e.g. you can use
softwareSystem
orsoftwaresystem
). - Double quote characters (
"..."
) are optional when a property contains no whitespace. - Opening curly brace symbols (
{
) must be on the same line (i.e. the last token of the statement, not on a line of their own). - Closing curly brace symbols (
}
) must be on a line of their own. - Opening/closing braces are only required when adding child content.
- Use
""
as a placeholder for an earlier optional property that you'd like to skip. - Each view must have a unique "key" (this is autogenerated if not specified).
- Tags are comma separated (e.g.
Tag 1,Tag 2,Tag 3
) - see Structurizr - Notation for details of how tags and styling works. - The Structurizr CLI will provide some default views and styles when they are not specified in your DSL - see Structurizr CLI - Defaults for details.
String substitution will take place on any text specified using the ${NAME}
syntax, where NAME
corresponds to a constant or an environment variable.
For example:
!constant ORGANISATION_NAME "Organisation"
!constant GROUP_NAME "Group"
workspace {
model {
enterprise "${ORGANISATION_NAME} - ${GROUP_NAME}" {
user = person "User"
}
}
}
If a named constant or environment variable cannot be found, the string will not be substituted.
Names may only contain the following characters: a-zA-Z0-9-_.
Comments can be defined as follows:
/*
multi-line comment
*/
/* single-line comment */
# single line comment
// single line comment
By default, all elements and relationships are anonymous, in that they can't be referenced from within the DSL. For example, the following statements will create a person and a software system, but neither can be referenced within the DSL.
person "User"
softwareSystem "Software System"
To create a relationship between the two elements, we need to be able to reference them. We can do this by defining an identifier, in the same way that you'd define a variable in many programming languages.
p = person "User"
ss = softwareSystem "Software System"
Now we can use these identifiers when creating relationships, specifying which elements should be included/excluded from views, etc.
p -> ss "Uses"
Identifiers are only needed where you plan to reference the element/relationship.
The !include
keyword can be used to include another file, to provide some degree of modularity, and to reuse definition fragments between workspaces.
!include <file|url>
The file must be a relative path, located within the same directory as the parent file, or a subdirectory of it. For example:
!include child.dsl
!include subdirectory/child.dsl
Alternatively, a HTTPS URL pointing to a single DSL file can be used.
The content of any included files is simply inlined into the parent document.
The !constant
keyword can be used to define a constant, which can be used with string substitution
!constant <name> <value>
Constant names may only contain the following characters: a-zA-Z0-9-_.
The Structurizr DSL supports a number of expressions for use when including or excluding elements/relationships on views.
-
-><identifier>
: the specified element plus afferent couplings -
<identifier>->
: the specified element plus efferent couplings -
-><identifier>->
: the specified element plus afferentand efferent couplings -
element.type==<type>
: elements of the specified type (Person|SoftwareSystem|Container|Component|DeploymentNode|InfrastructureNode|SoftwareSystemInstance|ContainerInstance) -
element.tag==<tag>[,tag]
: all elements that have all of the specified tags -
element.tag!=<tag>[,tag]
: all elements that do not have all of the specified tags -
element=-><identifier>
: the specified element plus afferent couplings -
element=<identifier>->
: the specified element plus efferent couplings -
element=-><identifier>->
: the specified element plus afferentand efferent couplings -
*->*
: all relationships -
<identifier>->*
: all relationships with the specified source element -
*-><identifier>
: all relationships with the specified destination element -
relationship==*
: all relationships -
relationship==*->*
: all relationships -
relationship.tag==<tag>[,tag]
: all relationships that have all of the specified tags -
relationship.tag!=<tag>[,tag]
: all relationships that do not have all of the specified tags -
relationship.source==<identifier>
: all relationships with the specified source element -
relationship.destination==<identifier>
: all relationships with the specified destination element -
relationship==<identifier>->*
: all relationships with the specified source element -
relationship==*-><identifier>
: all relationships with the specified destination element -
relationship==<identifier>-><identifier>
: all relationships between the two specified elements
Element and relationship expressions are not supported on dynamic views.
The following describes the language grammar, with angle brackets (<...>
) used to show required properties, and square brackets ([...]
) used to show optional properties.
Most statements are of the form: keyword <required properties> [optional properties]
workspace
is the top level language construct, and the wrapper for the model and views. A workspace can optionally be given a name and description.
workspace [name] [description] {
...
}
A workspace can also extend another workspace, to add more elements, relationships, views, etc to it.
workspace extends <file|url> {
...
}
The base workspace can either be referenced using a local DSL/JSON file, or a remote (via a HTTPS URL) DSL/JSON file. When extending a DSL-based workspace, all of the identifiers defined in that workspace are available to use in the extended workspace.
Permitted children:
- name
- description
- properties
- !docs
- !adrs
- model
- views
- configuration
Each workspace must contain a model
block, inside which elements and relationships are defined.
model {
...
}
Permitted children:
- impliedRelationships
- enterprise
- group
- person
- softwareSystem
- deploymentEnvironment
- element
- -> (relationship)
impliedRelationships <true|false>
The impliedRelationships
keyword provides a way to enable or disable whether implied relationships are created.
A flag of false
disables implied relationship creation, while true
creates implied relationships between all valid combinations of the parent elements, unless any relationship already exists between them
(see Structurizr for Java - Implied relationships - CreateImpliedRelationshipsUnlessAnyRelationshipExistsStrategy for more details).
The enterprise
keyword provides a way to define a named "enterprise" (e.g. an organisation) within the top-level model. Any people or software systems defined inside this block will be deemed to be "internal", while all others will be deemed to be "external". On System Landscape and System Context diagrams, an enterprise is represented as a dashed box. Only a single enterprise can be defined within a model.
enterprise <name> {
...
}
Permitted children:
The group
keyword provides a way to define a named grouping of elements, which will be rendered as a boundary around those elements.
See groups.dsl for an example.
group <name> {
...
}
Groups can be defined as follows:
Location | Permitted elements |
---|---|
Model | People and software systems |
Software System | Containers |
Container | Components |
Groups cannot be nested.
The person
keyword defines a person (e.g. a user, actor, role, or persona).
person <name> [description] [tags] {
...
}
The following tags are added by default:
Element
Person
Permitted children:
The softwareSystem
keyword defines a software system.
softwareSystem <name> [description] [tags] {
...
}
The following tags are added by default:
Element
Software System
Permitted children:
The container
keyword defines a container, within a software system.
container <name> [description] [technology] [tags] {
...
}
The following tags are added by default:
Element
Container
Permitted children:
The component
keyword defines a component, within a container.
component <name> [description] [technology] [tags] {
...
}
The following tags are added by default:
Element
Component
Permitted children:
The deploymentEnvironment
keyword provides a way to define a deployment environment (e.g. development, testing, staging, live, etc).
deploymentEnvironment <name> {
...
}
Permitted children:
The deploymentGroup
keyword provides a way to define a named deployment group.
deploymentGroup <name>
When software system/container instances are added to a deployment environment, all of the relationships between these elements are automatically replicated between all instances. Deployment groups provide a way to restrict the scope in which relationships are replicated. See deployment-groups.dsl for an example.
The deploymentNode
keyword is used to define a deployment node.
deploymentNode <name> [description] [technology] [tags] [instances] {
...
}
The following tags are added by default:
Element
Deployment Node
Permitted children:
- deploymentNode (deployment nodes can be nested)
- infrastructureNode
- softwareSystemInstance
- containerInstance
- -> (relationship)
- tags
- url
- properties
- perspectives
The infrastructureNode
keyword defines an infrastructure node, which is typically something like a load balancer, firewall, DNS service, etc.
infrastructureNode <name> [description] [technology] [tags] {
...
}
The following tags are added by default:
Element
Infrastructure Node
Permitted children:
The softwareSystemInstance
keyword defines an instance of the specified software system that is deployed on the parent deployment node.
softwareSystemInstance <identifier> [deploymentGroup|tags] [tags] {
...
}
The identifier
must represent a software system.
In addition to the software system's tags, the following tags are added by default:
-
Software System Instance
The containerInstance
keyword defines an instance of the specified container that is deployed on the parent deployment node.
containerInstance <identifier> [deploymentGroup|tags] [tags] {
...
}
The identifier
must represent a container.
In addition to the container's tags, the following tags are added by default:
-
Container Instance
The healthCheck
keyword defines a HTTP health check for the parent software system/container instance.
healthCheck <name> <url> [interval] [timeout]
The interval is a number of seconds (default 60s), and the timeout is a number of milliseconds (default 0ms).
The element
keyword defines a custom element (this is only available on the Structurizr cloud service/on-premises installation).
element <name> [metadata] [description] [tags] {
...
}
The following tags are added by default:
Element
Permitted children:
->
is used to define a uni-directional relationship between two elements.
There are two ways to define relationships. The first is explicitly, where you explicitly use a source identifier:
<identifier> -> <identifier> [description] [technology] [tags] {
...
}
For example:
user -> softwareSystem "Uses"
And the second is implicitly, where the relationship source is the element in scope:
-> <identifier> [description] [technology] [tags]
For example:
person user {
-> softwareSystem "Uses"
}
The following tags are added to relationships by default:
Relationship
The following types of relationships can be created using the DSL:
Source | Destination |
---|---|
Person | Person, Software System, Container, Component |
Software System | Person, Software System, Container, Component |
Container | Person, Software System, Container, Component |
Component | Person, Software System, Container, Component |
Deployment Node | Deployment Node |
Infrastructure Node | Deployment Node, Infrastructure Node, Software System Instance, Container Instance |
Software System Instance | Infrastructure Node |
Container Instance | Infrastructure Node |
Permitted children:
tags
is used to adds tags to an element or relationship. Tags can be specified comma separated, or individually.
tags "Tag 1"
tags "Tag 1,Tag 2"
tags "Tag 1" "Tag 2"
url
is used to set a URL on an element or relationship.
url https://example.com
The properties
block is used to define one or more name/value properties for an element or relationship.
properties {
<name> <value>
...
}
The perspectives
block is used to define one or more name/description perspectives for an element or relationship.
See Help - Perspectives for how these are used.
perspectives {
<name> <description>
...
}
Each workspace can also contain one or more views, defined with the views
block.
views {
...
}
The views
block can contain the following:
- systemLandscape
- systemContext
- container
- component
- filtered
- dynamic
- deployment
- custom
- styles
- theme
- themes
- branding
- terminology
The systemLandscape
keyword is used to define a System Landscape view.
systemLandscape [key] [description] {
...
}
Permitted children:
The systemContext
keyword is used to define a System Context view for the specified software system.
systemContext <software system identifier> [key] [description] {
...
}
Permitted children:
The container
keyword is used to define a Container view for the specified software system.
container <software system identifier> [key] [description] {
...
}
Permitted children:
The component
keyword is used to define a Component view for the specified container.
component <container identifier> [key] [description] {
...
}
Permitted children:
The filtered
keyword is used to define a Filtered view on top of the specified view.
filtered <baseKey> <include|exclude> <tags> [key] [description]
The baseKey
specifies the key of the System Landscape, System Context, Container, or Component view on which this filtered view should be based. The mode (include
or exclude
) defines whether the view should include or exclude elements/relationships based upon the tags
provided.
The dynamic
keyword defines a Dynamic view for the specified scope.
dynamic <*|software system identifier|container identifier> [key] [description] {
...
}
The first property defines the scope of the view, and therefore what can be added to the view, as follows:
*
scope: People and software systems.- Software system scope: People, other software systems, and containers.
- Container scope: People, other software systems, other containers, and components.
Unlike the other diagram types, Dynamic views are created by specifying the relationships that should be added to the view, within the dynamic
block, as follows:
<identifier> -> <identifier> [description] [technology]
With a dynamic view, you're showing instances of relationships that are defined in the static model. For example, imagine that you have two software systems defined in the static model, with a single relationship between them described as "Sends data to". A dynamic view allows you to override the relationship description, to better describe the interaction in the context of the behaviour you're diagramming. See dynamic.dsl for an example of this, and Modelling multiple relationships for some tips on how to best model multiple relationships between two elements in order to avoid cluttering your static model. For convenience, if a relationship between the two elements does not exist in the static model, the DSL parser will automatically create it for you.
See parallel.dsl for an example of how to create dynamic diagrams with parallel sequences.
Permitted children:
The deployment
keyword defines a Deployment view for the specified scope and deployment environment.
deployment <*|software system identifier> <environment> [key] [description] {
...
}
The first property defines the scope of the view, and the second property defines the deployment environment (which can be an identifier, or a name). The combination of these two properties determines what can be added to the view, as follows:
*
scope: All deployment nodes, infrastructure nodes, and container instances within the deployment environment.- Software system scope: All deployment nodes and infrastructure nodes within the deployment environment. Container instances within the deployment environment that belong to the software system.
Permitted children:
The custom
keyword is used to define a custom view (this is only available on the Structurizr cloud service/on-premises installation).
custom [key] [title] [description] {
...
}
Permitted children:
The include
keyword can be used to include elements or relationships.
To include elements in a view, use one or more include
statements inside the block defining the view.
include <*|identifier|expression> [identifier|expression...]
Elements can either be specified using individual identifiers, the wildcard identifier (*
), or a property expression.
The wildcard identifier (*
) operates differently depending upon the type of diagram, as follows:
- System Landscape view: Include all people and software systems.
- System Context view: Include the software system in scope; plus all people and software systems that are directly connected to the software system in scope.
- Container view: Include all containers within the software system in scope; plus all people and software systems that are directly connected to those containers.
- Component view: Include all components within the container in scope; plus all people, software systems and containers (belonging to the software system in scope) directly connected to them.
- Filtered view: (not applicable)
- Dynamic view: (not applicable)
- Deployment view: Include all deployment nodes, infrastructure nodes, and container instances defined within the deployment environment and (optional) software system in scope.
Element expressions are currently only supported on system landscape, system context, container, and component views. They provide a way to include elements based upon some basic conditional logic, as follows:
element.tag==<tag>,[tag]
: include elements that have all of the specified tagselement.tag!=<tag>,[tag]
: include elements that do not have all of the specified tags
To include a relationship in a view, you can specify an individual relationship identifier, or an expression:
include <identifier|expression> [identifier|expression...]
Relationship expressions only operate on elements that exist in the view.
The exclude
keyword can be used to exclude elements or relationships.
To exclude specific elements, use one or more exclude
statements inside the block defining the view.
exclude <identifier|expression> [identifier|expression...]
To exclude a relationship in a view, you can specify an individual relationship identifier, or use a property expression:
exclude <identifier|expression> [identifier|expression...]
Property expressions are currently only supported on system landscape, system context, container, and component views. They provide a way to exclude relationships based upon some basic conditional logic, as follows:
relationship.tag==<tag>,[tag]
: exclude relationships that have all of the specified tagsrelationship.tag!=<tag>,[tag]
: exclude relationships that do not have all of the specified tags
Alternatively, you can use the relationship expression syntax as follows:
exclude <*|identifier> -> <*|identifier>
The combinations of parameters are:
* -> *
: all relationships between all elementssource -> *
: all relationships fromsource
to any element* -> destination
: all relationships from any element todestination
source -> destination
: all relationships fromsource
todestination
The relationship expression syntax only operates on elements that exist in the view.
To enable automatic layout mode for the diagram, use the autoLayout
statement inside the block defining the view.
autoLayout [tb|bt|lr|rl] [rankSeparation] [nodeSeparation]
The first property is the rank direction:
tb
: Top to bottom (default)bt
: Bottom to toplr
: Left to rightrl
: Right to left
The second property is the separation of ranks in pixels (default: 300
), while the third property is the separation of nodes in the same rank in pixels (default: 300
).
The animation
keyword defines the animation for the specified view.
Each animation step should be defined on a separate line, inside the block, specifying the elements that should be included in that step.
animation {
<identifier> [identifier...]
<identifier> [identifier...]
}
Overrides the title of the view.
title <title>
styles
is the wrapper for one or more element/relationship styles, which are used when rendering diagrams.
styles {
...
}
Permitted children:
The element
keyword is used to define an element style. All nested properties (shape
, icon
, etc) are optional, see Structurizr - Notation for details about how tags and styles work.
element <tag> {
shape <Box|RoundedBox|Circle|Ellipse|Hexagon|Cylinder|Pipe|Person|Robot|Folder|WebBrowser|MobileDevicePortrait|MobileDeviceLandscape|Component>
icon <file>
width <integer>
height <integer>
background <#rrggbb>
color <#rrggbb>
colour <#rrggbb>
stroke <#rrggbb>
fontSize <integer>
border <solid|dashed|dotted>
opacity <integer: 0-100>
metadata <true|false>
description <true|false>
}
Please note that element styles are designed to work with the Structurizr cloud service/on-premises installation, and may not be fully supported by the PlantUML, Mermaid, etc export formats.
The relationship
keyword is used to define a relationship style. All nested properties (thickness
, color
, etc) are optional, see Structurizr - Notation for details about how tags and styles work.
relationship <tag> {
thickness <integer>
color #777777
colour #777777
dashed <true|false>
routing <Direct|Orthogonal|Curved>
fontSize <integer>
width <integer>
position <integer: 0-100>
opacity <integer: 0-100>
}
Please note that relationship styles are designed to work with the Structurizr cloud service/on-premises installation, and may not be fully supported by the PlantUML, Mermaid, etc export formats.
The theme
keyword can be used to specify a theme that should be used when rendering diagrams. See Structurizr - Themes for more details.
theme <default|url>
default
can be used as a theme URL, to include the default Structurizr theme.
The themes
keyword can be used to specify one or more themes that should be used when rendering diagrams. See Structurizr - Themes for more details.
themes <url> [url] ... [url]
default
can be used as a theme URL, to include the default Structurizr theme.
The branding
keyword allows you to define some custom branding that should be used when rendering diagrams and documentation. See Structurizr - Branding for more details.
branding {
logo <file>
font <name> [url]
}
The terminology
keyword allows you to override the terminology used when rendering diagrams (this may not be supported in all rendering tools). See Structurizr - Terminology for more details.
terminology {
enterprise <term>
person <term>
softwareSystem <term>
container <term>
component <term>
deploymentNode <term>
infrastructureNode <term>
relationship <term>
}
Finally, there are some configuration options that can be specified inside the configuration
block.
configuration {
...
}
Permitted children:
The users
block can be used to specify the users who should have read-only or read-write access to a workspace. Each username (e.g. e-mail address) and role pair should be specified on their own line. Valid roles are read
(read-only) and write
(read-write).
users {
<username> <read|write>
}
The !docs
keyword can be used to attach Markdown/AsciiDoc documentation to the parent context (either the workspace, or a software system).
!docs <path>
The path must be a relative path, located within the same directory as the parent file, or a subdirectory of it. For example:
!docs subdirectory
All Markdown and AsciiDoc files in this directory (and sub-directories) will be imported, alphabetically according to the filename. Each file must represent a separate documentation section, and the second level heading (## Section Title
in Markdown and == Section Title
in AsciiDoc) will be used as the section name.
The !adrs
keyword can be used to attach Markdown/AsciiDoc ADRs to the parent context (either the workspace, or a software system).
!adrs <path>
The path must be a relative path, located within the same directory as the parent file, or a subdirectory of it. For example:
!adrs subdirectory
All Markdown and AsciiDoc files in this directory (and sub-directories) will be imported, alphabetically according to the filename. The files must have been created by adr-tools, or at least follow the same format.