ArchiMate in Structurizr DSL — And Beyond¶
Context¶
The Semantic Architecture as Code article showed that RDF/Turtle can serve as an architecture DSL with ArchiMate's full semantic richness. But Turtle is verbose and unfamiliar to most developers.
This article asks three questions:
- Can we model ArchiMate semantics in Structurizr DSL — using its archetypes, tags, properties, and custom elements — and then convert to RDF?
- How does that compare to writing Turtle directly?
- Is there a better DSL — something with Structurizr's developer-friendliness AND Turtle's semantic richness?
1. Can Structurizr DSL Express ArchiMate? — A Practical Evaluation¶
Structurizr DSL has three extension mechanisms that could carry ArchiMate semantics:
1.1 Archetypes — user-defined element types¶
Since 2024, Structurizr supports archetypes: user-defined types that extend the basic C4 element types with default tags, technology, and properties.
archetypes {
businessActor = person {
tag "ArchiMate" "BusinessActor"
}
applicationComponent = softwareSystem {
tag "ArchiMate" "ApplicationComponent"
}
applicationService = container {
tag "ArchiMate" "ApplicationService"
}
applicationInterface = container {
tag "ArchiMate" "ApplicationInterface"
}
dataObject = container {
tag "ArchiMate" "DataObject"
}
node = deploymentNode {
tag "ArchiMate" "Node"
}
}
This lets you write:
model {
customer = businessActor "Customer"
orderMgmt = applicationComponent "Order Management" {
orderService = applicationService "Order Placement Service"
orderAPI = applicationInterface "Orders REST API"
ordersDB = dataObject "Order"
}
}
What works: Element typing. You can tag elements with ArchiMate types and a converter can read those tags to produce typed RDF.
What breaks:
- Archetypes are aliases for C4 types. An applicationService archetype is still a container underneath. Structurizr's view rules still apply — you can't put an applicationService in a System Context view because it's a container. ArchiMate's viewpoint rules are completely different.
- No cross-layer nesting. In ArchiMate, a Business Service can be realized by an Application Service. In Structurizr, a container can only live inside a software system. You can't nest a "Business Service" archetype inside a "Capability" archetype — the DSL doesn't allow it.
- Only 8 base types. Archetypes can only extend: person, softwareSystem, container, component, deploymentNode, infrastructureNode, group, element. ArchiMate has 62 element types across 7 layers. Many ArchiMate concepts (Capability, Value Stream, Goal, Principle, Requirement, Business Process, Technology Service) don't map cleanly to any C4 base type.
1.2 Custom elements — the element keyword¶
Structurizr's element keyword creates elements outside the C4 model:
model {
orderFulfillment = element "Order Fulfillment" "Capability" {
tag "ArchiMate" "Capability"
}
orderPlacement = element "Order Placement" "BusinessService" {
tag "ArchiMate" "BusinessService"
}
}
What works: You can create any ArchiMate element type as a custom element.
What breaks:
- Custom elements can only appear in custom views. They cannot appear in System Context, Container, Component, or Deployment views. This defeats the purpose — you can't show a Capability in the same diagram as an Application Component.
- No containment hierarchy. Custom elements are flat. You can't nest a Business Process inside a Business Actor, or an Application Function inside an Application Component.
- No typed relationships. All relationships are still labeled arrows. am:serves, am:realizes, am:accesses — these become free-text labels with no formal semantics.
1.3 Properties — key-value metadata¶
Structurizr elements can carry arbitrary properties:
orderMgmt = softwareSystem "Order Management" {
properties {
"archimate:type" "ApplicationComponent"
"archimate:layer" "Application"
"owner" "Orders Team"
"lifecycle" "production"
}
}
What works: A converter can read these properties and produce typed RDF.
What breaks: Properties are opaque strings. Structurizr doesn't validate them. You can write "archimate:type" "Bananaphone" and Structurizr won't complain. There's no schema, no validation, no auto-completion.
1.4 Relationship archetypes¶
Structurizr supports relationship archetypes with default tags and technology:
archetypes {
serves = -> { tags "ArchiMate" "Serving" }
realizes = -> { tags "ArchiMate" "Realization" }
accesses = -> { tags "ArchiMate" "Access" }
composedOf = -> { tags "ArchiMate" "Composition" }
assignedTo = -> { tags "ArchiMate" "Assignment" }
}
orderService --realizes-> orderPlacement "Realizes"
orderAPI --serves-> customer "Serves"
What works: Relationship typing via tags. A converter can read the tags.
What breaks: The tags are just strings. Structurizr doesn't enforce that a realizes relationship can only go from an Application Service to a Business Service. Any element can realizes any other element. The ArchiMate relationship validity matrix (which source types can connect to which target types via which relationship types) is completely unenforced.
1.5 Verdict: Possible but Leaky¶
You CAN model ArchiMate in Structurizr DSL using archetypes + tags + properties + relationship archetypes. A converter can read the tags and properties and produce typed RDF. But:
| ArchiMate Capability | Structurizr DSL Support | Gap |
|---|---|---|
| 62 element types | ⚠️ Via archetypes + custom elements + tags | Only 8 base types; custom elements can't appear in standard views |
| 7 layers with cross-layer nesting | ❌ | C4 nesting rules (System → Container → Component) don't match ArchiMate layers |
| 11 typed relationship types | ⚠️ Via relationship archetypes + tags | No validation of source/target type constraints |
| Relationship validity matrix | ❌ | Structurizr doesn't validate which types can connect via which relationships |
| Viewpoints (23+ with element/relationship filtering) | ❌ | Structurizr views are C4-scoped, not ArchiMate-scoped |
| Derivation rules | ❌ | No inference capability |
| Cross-layer traceability queries | ❌ | No query language |
The result is ArchiMate-flavored C4, not actual ArchiMate. The types are carried as metadata, but the structural rules, viewpoint constraints, and relationship semantics are lost. A converter to RDF would recover the semantics, but the authoring experience in Structurizr DSL doesn't enforce them.
2. The Full Example: ArchiMate in Structurizr DSL¶
Despite the limitations, here's what the best-effort ArchiMate-in-Structurizr looks like:
workspace "Order Management Architecture" {
model {
archetypes {
# ArchiMate element archetypes
businessActor = person { tag "am:BusinessActor" }
capability = element { tag "am:Capability" }
businessService = element { tag "am:BusinessService" }
applicationComponent = softwareSystem { tag "am:ApplicationComponent" }
applicationService = container { tag "am:ApplicationService" }
applicationInterface = container { tag "am:ApplicationInterface" }
dataObject = container { tag "am:DataObject" }
techNode = deploymentNode { tag "am:Node" }
systemSoftware = deploymentNode { tag "am:SystemSoftware" }
# ArchiMate relationship archetypes
serves = -> { tags "am:Serving" }
realizes = -> { tags "am:Realization" }
accesses = -> { tags "am:Access" }
composedOf = -> { tags "am:Composition" }
assignedTo = -> { tags "am:Assignment" }
}
# ── Strategy / Business ──────────────────────────
orderFulfillment = capability "Order Fulfillment"
orderPlacementBiz = businessService "Order Placement"
# ── People ───────────────────────────────────────
customer = businessActor "Customer"
# ── Application Layer ────────────────────────────
orderMgmt = applicationComponent "Order Management" {
properties {
"owner" "Orders Team"
}
orderPlacementSvc = applicationService "Order Placement Service"
orderAPI = applicationInterface "Orders REST API"
ordersAPIComp = container "Orders API" "Handles order lifecycle" "Spring Boot"
ordersDB = container "Orders DB" "Stores orders" "PostgreSQL"
ordersWorker = container "Orders Worker" "Processes events" "Spring Boot"
orderData = dataObject "Order"
}
paymentSystem = applicationComponent "Payment System" "External"
# ── Relationships ────────────────────────────────
customer --serves-> orderAPI "Uses"
orderPlacementSvc --realizes-> orderPlacementBiz
orderPlacementBiz --realizes-> orderFulfillment
ordersAPIComp --serves-> ordersDB "Reads/writes" "JDBC"
ordersAPIComp --serves-> ordersWorker "Sends events" "AMQP"
ordersAPIComp --serves-> paymentSystem "Processes payments" "HTTPS"
ordersAPIComp --accesses-> orderData "Reads/writes"
ordersAPIComp --assignedTo-> orderPlacementSvc
# ── Deployment ───────────────────────────────────
production = deploymentEnvironment "Production" {
aws = techNode "AWS eu-west-1" {
eks = techNode "EKS Cluster" "" "Kubernetes 1.28" {
containerInstance ordersAPIComp
containerInstance ordersWorker
}
rds = techNode "RDS" "" "PostgreSQL 15" {
containerInstance ordersDB
}
}
}
}
views {
# Standard C4 views still work
container orderMgmt "Containers" {
include *
autolayout lr
}
deployment orderMgmt production "Production" {
include *
autolayout lr
}
# Custom view for ArchiMate cross-layer
custom "BusinessAlignment" "Business Alignment" {
include orderFulfillment
include orderPlacementBiz
include orderPlacementSvc
include orderMgmt
autolayout tb
}
styles {
element "am:Capability" {
shape roundedbox
background #f0e68c
}
element "am:BusinessService" {
shape roundedbox
background #ffe4b5
}
element "am:ApplicationService" {
background #b0e0e6
}
element "am:DataObject" {
shape cylinder
background #d3d3d3
}
}
}
}
What this achieves: A developer-readable file in Git that carries ArchiMate type information via tags and can be converted to RDF. The C4 Container and Deployment views still work. A custom view shows the cross-layer alignment.
What this loses: No SHACL validation. No relationship validity checking. No derivation rules. No SPARQL queries. The cross-layer view is manually curated, not automatically generated from viewpoint definitions. The ArchiMate types are metadata, not enforced structure.
3. Comparison: Structurizr DSL vs Turtle vs Alternatives¶
3.1 The same model in three formats¶
Structurizr DSL (~40 lines of model, shown above) - Readable by any developer - Tags carry ArchiMate types - No semantic validation - Converter needed to produce RDF
RDF/Turtle (~50 lines, from the previous article) - Full ArchiMate semantics - SHACL validation - SPARQL queryable - Verbose, unfamiliar syntax
YAML-LD (hypothetical — what it could look like):
"@context":
am: https://meta.linked.archi/archimate3/onto#
bs: https://meta.linked.archi/backstage/onto#
arch: https://meta.linked.archi/core#
skos: http://www.w3.org/2004/02/skos/core#
ex: https://model.example.com/orders#
"@graph":
- "@id": ex:OrderFulfillment
"@type": am:Capability
skos:prefLabel: "Order Fulfillment"
- "@id": ex:OrderPlacement
"@type": am:BusinessService
skos:prefLabel: "Order Placement"
am:realizes: { "@id": ex:OrderFulfillment }
- "@id": ex:OrderManagement
"@type": am:ApplicationComponent
skos:prefLabel: "Order Management"
bs:ownedBy: { "@id": ex:OrdersTeam }
am:composedOf:
- { "@id": ex:OrdersAPI }
- { "@id": ex:OrdersDB }
- "@id": ex:OrderPlacementService
"@type": am:ApplicationService
skos:prefLabel: "Order Placement Service"
am:realizes: { "@id": ex:OrderPlacement }
- "@id": ex:OrdersAPI
"@type": am:ApplicationComponent
skos:prefLabel: "Orders API"
skos:definition: "Handles order lifecycle"
am:serves: { "@id": ex:PaymentSystem }
am:accesses: { "@id": ex:Order }
am:assignedTo: { "@id": ex:SpringBoot }
LinkML YAML (hypothetical — schema-driven):
# Defined by a LinkML schema that maps to ArchiMate ontology
elements:
- id: order-fulfillment
type: Capability
label: "Order Fulfillment"
- id: order-placement
type: BusinessService
label: "Order Placement"
realizes: order-fulfillment
- id: order-management
type: ApplicationComponent
label: "Order Management"
owner: orders-team
composed_of: [orders-api, orders-db, orders-worker]
- id: order-placement-service
type: ApplicationService
label: "Order Placement Service"
realizes: order-placement
- id: orders-api
type: ApplicationComponent
label: "Orders API"
description: "Handles order lifecycle"
technology: "Spring Boot"
serves: [payment-system]
accesses: [order-data]
assigned_to: [order-placement-service]
3.2 Comparison matrix¶
| Dimension | Structurizr DSL | RDF/Turtle | YAML-LD | LinkML YAML |
|---|---|---|---|---|
| Readability | ✅ Excellent | ⚠️ Moderate (prefix-heavy) | ⚠️ Moderate (JSON-LD verbosity) | ✅ Excellent |
| Learning curve | ✅ Hours | ⚠️ Days | ⚠️ Days (JSON-LD context) | ✅ Hours (just YAML) |
| ArchiMate type system | ⚠️ Via tags (unenforced) | ✅ Native OWL classes | ✅ Native (via @type) | ✅ Via schema (validated) |
| Typed relationships | ⚠️ Via tags (unenforced) | ✅ Native OWL properties | ✅ Native (via predicates) | ✅ Via schema slots |
| Relationship validation | ❌ | ✅ SHACL | ✅ SHACL (after conversion) | ✅ LinkML validation |
| Cross-layer traceability | ❌ (manual custom views) | ✅ SPARQL | ✅ SPARQL (after conversion) | ✅ (after RDF generation) |
| SPARQL queryable | ❌ | ✅ Native | ✅ (is RDF) | ✅ (generates RDF) |
| AI agent access (MCP) | ❌ | ✅ | ✅ | ✅ (via generated RDF) |
| Diagram generation | ✅ Native (polished) | ⚠️ Via generators | ⚠️ Via generators | ⚠️ Via generators |
| Git-friendly | ✅ | ✅ | ✅ | ✅ |
| IDE support | ✅ (VS Code extension) | ⚠️ (generic Turtle highlighting) | ⚠️ (YAML highlighting) | ✅ (YAML + schema validation) |
| Ecosystem maturity | ✅ Mature | ✅ Mature (W3C) | ⚠️ Emerging (W3C CG) | ⚠️ Growing (CNCF-adjacent) |
| Converter to RDF needed | Yes (custom) | No (is RDF) | No (is RDF) | Yes (built-in gen-rdf) |
4. The Options — Ranked¶
Option A: Structurizr DSL + Converter (pragmatic, limited)¶
How it works: Teams write Structurizr DSL with ArchiMate archetypes and tags. A custom converter reads the Structurizr workspace JSON and produces RDF typed with ArchiMate classes.
Pros: - Developers already know Structurizr DSL - Polished diagram generation - Existing ecosystem (VS Code extension, Lite, Cloud)
Cons: - ArchiMate semantics are metadata, not structure — no validation at authoring time - Cross-layer modeling is awkward (custom elements in custom views) - Converter must be built and maintained - Two representations to keep in sync (DSL + generated RDF)
Best for: Teams already using Structurizr that want to gradually add ArchiMate semantics without changing their workflow.
Option B: RDF/Turtle directly (powerful, verbose)¶
How it works: Teams write Turtle files directly, as shown in the Semantic Architecture as Code article.
Pros: - Full ArchiMate semantics, no compromises - SHACL validation at authoring time - SPARQL queryable immediately - No converter needed - MCP server access immediately
Cons: - Turtle syntax is unfamiliar to most developers - Verbose (prefix declarations, IRI syntax) - No native diagram generation (need generators) - IDE support is basic (syntax highlighting, no schema-aware auto-completion)
Best for: Architecture teams comfortable with semantic web technologies, or organizations where the EA team authors models and developers consume generated outputs.
Option C: YAML-LD (semantic, familiar syntax)¶
How it works: Teams write YAML files with a JSON-LD @context that maps keys to ArchiMate ontology IRIs. The YAML is valid RDF (via the YAML-LD specification) and can be loaded directly into a triplestore.
Pros: - YAML is familiar to every developer (Kubernetes, CI/CD, Backstage) - Full RDF semantics (it IS RDF, just in YAML syntax) - No converter needed — YAML-LD parsers produce RDF directly - SHACL validation works on the parsed RDF
Cons:
- YAML-LD is a W3C Community Group specification, not yet a full standard
- The @context / @graph / @id / @type syntax adds JSON-LD ceremony
- Tooling is immature compared to Turtle or JSON-LD
- No native diagram generation
Best for: Organizations that want semantic precision in a developer-familiar format and are willing to adopt an emerging standard.
Option D: LinkML YAML + ArchiMate Schema (best of both worlds?)¶
How it works: Define an ArchiMate schema in LinkML (a YAML-based data modeling language). Teams write architecture models as plain YAML conforming to the schema. LinkML generates RDF, JSON Schema, SHACL shapes, and documentation from the schema.
Pros:
- Authoring is plain YAML — no @context, no prefixes, no IRIs
- Schema provides validation and auto-completion at authoring time
- LinkML generates RDF/OWL, SHACL, JSON Schema, Python dataclasses, documentation
- The schema IS the metamodel — ArchiMate element types, relationship constraints, and cardinalities are defined once
- Active community (biomedical data, CNCF-adjacent)
Cons: - Requires defining an ArchiMate schema in LinkML (significant upfront work) - LinkML's relationship modeling is less expressive than OWL for qualified relationships - Generated RDF may not perfectly match Linked.Archi's qualified relationship pattern without customization - Another tool in the chain
Best for: Organizations that want the simplest possible authoring experience with full semantic validation, and are willing to invest in schema definition upfront.
Option E: A Linked.Archi DSL (hypothetical — purpose-built)¶
How it works: A purpose-built DSL designed specifically for semantic architecture modeling, combining Structurizr's terseness with ArchiMate's type system.
What it could look like:
@metamodel archimate 3.2
@namespace ex https://model.example.com/orders#
# ── Strategy ─────────────────────────────────────
capability "Order Fulfillment"
# ── Business ─────────────────────────────────────
business-service "Order Placement"
realizes "Order Fulfillment"
business-actor "Customer"
# ── Application ──────────────────────────────────
application-component "Order Management"
owner "Orders Team"
composed-of "Orders API", "Orders DB", "Orders Worker"
application-service "Order Placement Service"
realizes "Order Placement"
application-component "Orders API"
description "Handles order lifecycle"
technology "Spring Boot"
serves "Payment System"
accesses "Order"
assigned-to "Order Placement Service"
application-component "Orders DB"
description "Stores orders"
technology "PostgreSQL"
data-object "Order"
# ── Technology ───────────────────────────────────
node "EKS Cluster"
system-software "Kubernetes 1.28"
deploys "Orders API", "Orders Worker"
node "RDS Instance"
system-software "PostgreSQL 15"
deploys "Orders DB"
Pros:
- Extremely readable — no prefixes, no IRIs, no @context
- ArchiMate types are keywords, not tags
- Relationships are typed by the DSL grammar
- A parser produces RDF aligned to the Linked.Archi ontology
- SHACL validation runs on the output
- Could support Structurizr-style view definitions
Cons: - Doesn't exist yet — requires designing and implementing a parser - Another DSL to learn (though simpler than Turtle or Structurizr) - Maintenance burden of a custom language - Risk of reinventing what LinkML already provides
Best for: The Linked.Archi ecosystem, if the community decides the authoring experience is the critical adoption barrier.
5. Recommendation¶
There is no single best option. The choice depends on where the organization is:
| Starting point | Recommended path |
|---|---|
| Already using Structurizr, want to add semantics gradually | Option A — Structurizr DSL + converter. Keep the developer workflow, add ArchiMate tags, build a converter. |
| EA team comfortable with semantic web, developers consume outputs | Option B — Turtle directly. Maximum power, no compromises. Developers never see Turtle — they see generated Markdown and HTML. |
| Want semantic precision in a developer-familiar format | Option C or D — YAML-LD or LinkML. YAML authoring with RDF output. LinkML adds schema validation. |
| Building the Linked.Archi ecosystem and want maximum adoption | Option E — Purpose-built DSL. Highest investment, highest payoff for developer experience. |
| Want to start today with minimal investment | Option A (if using Structurizr) or Option B (if not). Both work now with existing tools. |
The Linked.Archi ecosystem already supports Option B (Turtle) natively and Option A (via the PlantUML converter, which could be extended for Structurizr JSON). Options C, D, and E represent future directions that could dramatically lower the authoring barrier while preserving semantic richness.
6. What a Structurizr-to-RDF Converter Would Do¶
For teams choosing Option A, here's what the converter pipeline looks like:
flowchart TD
DSL["Structurizr DSL"]
JSON["Structurizr Workspace JSON"]
RDF["RDF/Turtle<br/>(aligned to Linked.Archi ontology)"]
SHACL["SHACL validation"]
SPARQL["SPARQL queries"]
MCP["MCP server (AI agents)"]
Docs["rdf2docs (Markdown generation)"]
Nav["Static navigator (web UI)"]
DSL -->|"Structurizr CLI: export to JSON"| JSON
JSON -->|"structurizr-to-rdf converter"| RDF
RDF --> SHACL & SPARQL & MCP & Docs & Nav
The converter would:
- Read the Structurizr workspace JSON (exported via
structurizr-cli export -f json) - Map C4 element types to ArchiMate classes based on tags:
- Tag
am:ApplicationComponent→a am:ApplicationComponent - Tag
am:BusinessService→a am:BusinessService - No ArchiMate tag → fall back to C4 ontology types (
c4:Container,c4:SoftwareSystem) - Map relationship archetypes to ArchiMate predicates based on tags:
- Tag
am:Serving→am:serves+am:Servingqualified relationship - Tag
am:Realization→am:realizes+am:Realizationqualified relationship - No ArchiMate tag →
c4:useswith the label as description - Map properties to RDF properties:
"owner"→bs:ownedBy"lifecycle"→bs:lifecycle"technology"→c4:technology- Produce three named graphs: semantic, views, provenance (following the Linked.Archi converter convention)
- Emit SKOS labels from element names and descriptions
This converter fits naturally alongside the existing ArchiMate, BPMN, and PlantUML converters in the Linked.Archi toolbox.
7. Summary¶
| Question | Answer |
|---|---|
| Can Structurizr DSL express ArchiMate? | Partially. Element types via archetypes/tags, relationship types via relationship archetypes. But no structural enforcement, no cross-layer nesting, no relationship validity, no viewpoint rules. |
| Is it worth doing? | Yes, for teams already using Structurizr. The tags carry enough information for a converter to produce semantically rich RDF. The authoring experience is familiar. |
| Is Turtle better? | Semantically, yes — full ArchiMate with SHACL validation. Practically, it depends on who's authoring. EA teams: Turtle works. Developers: too verbose. |
| Is there a better DSL? | YAML-LD and LinkML are promising alternatives that combine YAML familiarity with RDF semantics. A purpose-built Linked.Archi DSL could offer the best developer experience but requires investment to build. |
| What should I do today? | If using Structurizr: add ArchiMate archetypes and tags, plan a converter. If not: write Turtle directly and generate developer-friendly outputs. Either way, the knowledge graph is the goal. |
References¶
- Structurizr DSL — Archetypes — User-defined types
- Structurizr DSL — Custom Elements — Elements outside C4
- Structurizr DSL — Language Reference — Full DSL syntax
- YAML-LD Specification — W3C Community Group
- LinkML — Linked Data Modeling Language — YAML-based schema language with RDF generation
- LinkML FAQ: Why LinkML?
- JSON-LD — JSON for Linked Data
- Semantic Architecture as Code — The Turtle-based approach
- How Linked.Archi Bridges the Gap — The broader adoption story
- C4/Structurizr and ArchiMate — The balanced comparison