Appearance
Model file structure (.cmn)
This page explains how a Canonical Model Notation (CMN) model file is structured and how elements in different files reference each other.
A CMN file has two main parts:
- a header – package, layer, imports, platform selection
- the content – types, services, resources, components, applications, …
Understanding this structure helps you organise larger models and reuse elements across packages and modules.
1. Header
The header appears at the top of a .cmn file and typically contains:
- the package (and optional layer)
- one or more imports (with optional aliases)
- the platform specification for the model
A simplified example:
text
package com.example.main
import com.example.core as core
import org.joinedworkz.facilities.common.base.api
platform SpringBoot exclude DtoCartridge1.1 Package and layer
Every CMN file belongs to a package. The package:
- defines the namespace of the elements declared in the file,
- is part of the fully qualified name of each element,
- is used by platforms for naming (e.g. Java packages) and outlet routing.
Later, models can optionally specify a layer in addition to the package. Layers are used by platforms and cartridges to route generated artifacts (for example via outlet overrides) and apply different rules to different parts of the model. Layers are explained in more detail in the Modeling section on layers and outlet routing.
1.2 Imports and aliases
Imports make elements from other packages available in the current file without having to use fully qualified names everywhere.
A basic import looks like:
text
import org.joinedworkz.facilities.common.base.apiYou can also define an alias for the imported package:
text
import com.example.core as coreThe alias can then be used as a prefix when referencing elements from that package, using the alias::Name syntax. For example:
text
type Info {
createdAt: core::DateTime
}Here:
coreis the alias defined in the import,DateTimeis a type defined in thecom.example.corepackage,core::DateTimeis an explicit reference to that type.
This has a few advantages:
- your model stays readable even with longer package names,
- you can clearly see from which package a referenced element comes,
- you avoid ambiguities when different packages define elements with the same simple name.
If you do not use an alias, you can either rely on simple names (if there is no ambiguity) or use fully qualified names where supported by the DSL.
1.3 Platform specification
The platform specification selects the platform that should be used for this model file (or for the package/module it belongs to).
A simple platform declaration looks like:
text
platform SpringBootThis tells the generator to use the SpringBoot platform defined in a .profil file. The platform controls which cartridges and generators are applied to the model and how they interpret its elements.
You can also exclude specific cartridges from the platform for this model, for example:
text
platform SpringBoot exclude DtoCartridgeIn this case:
- the
SpringBootplatform is still used, - all its normal cartridges apply,
- except the cartridge named
DtoCartridge, which is disabled for this model.
This allows you to fine-tune generation behaviour without changing the platform profile itself. Typical use cases include:
- disabling a cartridge for experimental or partial migrations,
- avoiding generation of certain artifacts for specific modules,
- temporarily turning off a cartridge while adjusting its configuration.
2. Content: model elements
After the header, a CMN file contains the model elements that make up your canonical model. The main categories are:
- data types – simple, complex types and enums
- services – operations representing business capabilities
- resources – externally visible APIs (e.g. REST endpoints)
- components – group resources/services into deployable units
- applications – top-level compositions of components
These elements are described conceptually in:
Within the same file, you can define multiple elements of each kind. All of them share the package from the header.
2.1 Subpackages
To structure larger models, you can define subpackages inside a package using the subpackage keyword. For example:
text
package com.example.main
import ...
platform SpringBoot
subpackage sub1 {
// model elements of com.example.main.sub1
}
subpackage sub2.sub3 {
// model elements of com.example.main.sub2.sub3
}In this example:
- elements inside
subpackage sub1 { ... }belong to the packagecom.example.main.sub1, - elements inside
subpackage sub2.sub3 { ... }belong tocom.example.main.sub2.sub3.
Subpackages help you:
- group related model elements without splitting them into many files,
- reflect a logical hierarchy inside a larger package,
- keep the header (imports, platform) in one place while structuring the content.
Each subpackage shares the imports and platform specification of the parent package; you do not need to repeat them inside the subpackage block.
3. Referencing model elements
CMN models frequently reference elements defined:
- in the same file,
- in other files of the same package,
- in other packages (via imports and aliases).
3.1 Same package
Within the same package, you normally reference elements by their simple name, for example:
text
type Greeting {
message: String
}
resource /hello as Greeting {
create()
read()
}Here, Greeting is a type defined in the same package, so no prefix or qualification is needed.
3.2 Imported packages and aliases
When referencing elements from imported packages, you typically:
- import the package,
- optionally assign an alias,
- use the alias with the
alias::Namesyntax.
Example:
text
import com.example.core as core
type Info {
createdAt: core::DateTime
}This makes it clear that DateTime comes from com.example.core. If you have multiple imports defining a type called DateTime, using aliases avoids ambiguity.
3.3 Fully qualified references
Depending on the exact DSL rules, you may also be able to use fully qualified names directly for some references, for example:
text
type Info {
createdAt: com.example.core::DateTime
}In practice, aliases are usually preferred for readability, especially when the same external package is used in many places.
4. Summary
A CMN model file is structured into:
- a header, which defines:
- the package (and optional layer),
- imports and aliases,
- the platform and optional cartridge exclusions;
- a content section with the actual model elements:
- types, services, resources, components, applications,
- optionally organised into subpackages.
References between elements rely on:
- simple names within the same package,
- imports and aliases for other packages (
alias::Name), - and, where appropriate, fully qualified names.
Keeping this structure in mind makes it easier to:
- split models across multiple files and packages,
- share common types via imported base models,
- control platform behaviour per package or module,
- and maintain large models over time.
