Skip to content

Extending model

You extend the model by creating new files and folders.
When LikeC4 source files are parsed, they are “merged” into a single architecture model.

You are free to organize the workspace as you want.

Assume we have the following workspace:

  • Directorycloud
    • service1.c4
    • service2.c4
  • Directoryexternals
    • amazon.c4
  • landscape.c4
  • specs.c4

This file defines the specification:

specification {
element actor {
style {
shape person
}
}
element system
element service
}

extend is a way to enrich the model and define nested elements in a separate file.

We don’t want to mess up the landscape.c4 file with the internals of the cloud.
In a separate file we extend cloud and define cloud.service1:

cloud/service1.c4
model {
// cloud is defined in landscape.c4
extend cloud {
// extend and define cloud.service1
service1 = service 'Service 1'
}
}

The element extension inherits the scope of the target (or better say parent).
For example:

cloud/service2.c4
model {
// cloud is defined in landscape.c4
extend cloud {
// extend and define cloud.service2
service2 = service 'Some Service 2'
service2 -> service1 // ✅ service1 is known inside 'cloud'
}
}

You can extend element with additional tags, links and metadata:

model {
extend cloud {
// Add tags
#additional-tag, #another-tag
// Add metadata
metadata {
prop1 'value1'
}
// Add links
link ../src/index.ts#L1-L10
}
}

When extending elements with metadata, duplicate keys from both the original element and the extension are merged into arrays:

model {
component api {
metadata {
version '1.0.0'
tags 'backend'
regions 'us-east-1'
}
}
}
// In another file
model {
extend api {
metadata {
tags 'microservice' // Merges with existing 'backend'
regions ['eu-west-1'] // Merges with existing 'us-east-1'
owner 'platform-team' // New key
}
}
}
// Result:
{
version: '1.0.0',
tags: ['backend', 'microservice'], // Merged and kept as array
regions: ['us-east-1', 'eu-west-1'], // Merged and kept as array
owner: 'platform-team'
}

Merging behavior:

  • Duplicate values are automatically de-duplicated
  • If after de-duplication there’s only one unique value, it’s stored as a string (not an array)
  • Arrays from both sides are merged and de-duplicated
model {
component api {
metadata {
environment 'production'
tags ['backend', 'api']
}
}
}
model {
extend api {
metadata {
environment 'production' // Duplicate value
tags ['api', 'critical'] // 'api' is duplicate
}
}
}
// Result:
{
environment: 'production', // Single value (de-duplicated)
tags: ['backend', 'api', 'critical'] // Merged and de-duplicated
}

You can extend the same element multiple times across different files, and all metadata will be properly merged:

file1.c4
model {
component api {
metadata {
version '2.0.0'
tags 'backend'
}
}
}
// file2.c4
model {
extend api {
metadata {
tags 'rest'
owner 'team-a'
}
}
}
// file3.c4
model {
extend api {
metadata {
tags 'microservice'
regions ['us', 'eu']
}
}
}
// Result:
{
version: '2.0.0',
tags: ['backend', 'rest', 'microservice'],
owner: 'team-a',
regions: ['us', 'eu']
}