Graph metamodels define which objects and relations appear in diagrams. Without a metamodel configuration, the diagram tab on an object page shows nothing.
Metamodel Structure
A graph metamodel is a package asset that describes the diagram rendering rules. It specifies which object types appear as nodes, which relations draw connecting lines, and how the diagram lays out by default.
Top-Level Properties
| Property | Type | Purpose |
|---|---|---|
key | string | Unique identifier for this metamodel within the package |
name | string | Display name shown in the diagram tab dropdown |
viewTypeKey | string | Diagram rendering type — determines visual behavior |
description | string | Optional description of the metamodel’s purpose |
isDefault | boolean | Whether this is the primary metamodel for the application |
state | string | Lifecycle state (active, inactive, in-validation, hidden) |
defaultDisableAutoLayout | boolean | When true, auto-layout is off by default |
defaultDisableShowAllPaths | boolean | When true, “show all paths” is off by default |
View Types
The viewTypeKey determines how the diagram engine renders nodes and edges:
| View type | Rendering behavior |
|---|---|
data_lineage | Directed graph showing data flow between objects. Nodes arranged left-to-right or top-to-bottom. |
entity_relation | Entity-relationship diagram with entity boxes and relationship lines. |
relation | Flexible graph showing all object relations. Used for knowledge graphs. |
conceptual_model | Free-form diagram for manual modeling. Special validation rules apply (see Relation Types below). |
Display Levels
The displayLevels array defines which object types appear as nodes in the diagram and how they nest visually.
Each display level entry maps one or more object types to a visual tier:
| Property | Type | Purpose |
|---|---|---|
key | string | Unique identifier for this display level |
name | string | Label shown in the diagram legend |
displayTypeKey | string | Required. Visual shape of the node (see table below) |
parentKey | string | Key of the parent display level — creates visual nesting |
isSingleHideable | boolean | Whether this level can be individually hidden in the UI |
isSelfTargeting | boolean | Whether nodes at this level can have self-referencing relations |
objectTypes | array | Which object types appear at this level (array of { "objectTypeKey": "..." }) |
Display Type Keys (grouped by diagram type)
Data Lineage nodes: folder (containers), object (data objects), column (child attributes — must have parentKey)
Entity-Relationship nodes: er_object (entities), er_column (entity attributes — must have parentKey)
Knowledge Graph nodes: knowledge_object (round-cornered nodes)
Conceptual Model nodes: simple, conceptual_folder, nonagon, circle, cylinder, rhombus, diamond, hexagon, rightwards_step
Nesting with parentKey
Nesting via parentKey is a necessity for data_lineage and entity_relation diagrams — it defines the visual hierarchy (databases containing schemas containing tables). Levels without parentKey sit at the diagram root.
{
"displayLevels": [
{ "key": "database", "name": "Database", "displayTypeKey": "folder" },
{ "key": "schema", "name": "Schema", "displayTypeKey": "folder", "parentKey": "database" },
{ "key": "table", "name": "Table", "displayTypeKey": "object", "parentKey": "schema" },
{ "key": "column", "name": "Column", "displayTypeKey": "column", "parentKey": "table" }
]
}
Tables render inside schemas, which render inside databases. column and er_column display types must have a parentKey — the backend rejects column-type levels at the diagram root.
Nesting supports mixed-depth hierarchies. For example, Tableau connectors may have folder→folder→folder→report but also folder→report — the same display level key can appear at different depths.
isSingleHideable — Critical for Lineage
This property controls whether users can individually hide a display level in the diagram UI while keeping the remaining hierarchy understandable. Only relevant for data_lineage diagrams.
Consider a hierarchy: department → database → table → column.
- Hiding “department” makes sense (
isSingleHideable: true) — it’s supplementary context, and database → table → column is still clear. - Hiding “table” does NOT make sense (
isSingleHideable: false) — without it, database → column is a confusing hierarchy.
Set isSingleHideable: true on levels that are “bonus context” and false on levels essential for understanding the data structure.
Relation Types
The relationTypes array specifies which relations draw connecting lines between nodes.
| Property | Type | Purpose |
|---|---|---|
key | string | Relation type key. Use cross-package FQN format: {packageKey}#{relationTypeKey} |
lineDisplayTypeKey | string | Required. Edge visual style (see table below) |
isDefault | boolean | Pre-selection when drawing lines (see explanation below) |
Line Display Type Keys (grouped by diagram type)
Data Lineage edges: data_lineage (solid directional arrow), indirect_flow (dotted arrow for transitive flow)
Entity-Relationship edges: foreign_key (ER relationship line), crows_foot (cardinality notation)
Knowledge Graph edges: knowledge_relation (thin line), knowledge_parent (thick line for parent-child)
Conceptual Model edges: association (simple line), specialization (inheritance arrow), verbal_concept (curved line), standard (default style)
How isDefault Works
isDefault determines which relation type is pre-selected when a user draws a new line of a given lineDisplayTypeKey in the diagram editor. Multiple relation types can share the same lineDisplayTypeKey — the default one is offered first, but the user can switch to any other relation type with the same line style.
For conceptual_model metamodels, the backend enforces a stricter rule: exactly one relation type per lineDisplayTypeKey must be marked as default. Missing or duplicate defaults cause an installation error.
For other metamodel types (data_lineage, entity_relation, relation), no validation is enforced on isDefault.
Single-Direction Rule for Data Lineage
Data lineage metamodels must use single-direction (oriented) relations only. Never include bidirectional relations in a data flow diagram — always only one line between two nodes. This is not validated by the backend but violating it produces confusing, unreadable diagrams with double arrows.
{
"relationTypes": [
{ "key": "core#hasDatasource", "lineDisplayTypeKey": "data_lineage", "isDefault": true },
{ "key": "core#foreign_key_parent", "lineDisplayTypeKey": "foreign_key", "isDefault": false }
]
}
User Relation Types
The userRelationTypes array controls which ownership roles display on diagram nodes. When configured, nodes show badges indicating the assigned owner, steward, or other role holder.
| Property | Type | Purpose |
|---|---|---|
key | string | User relation type key (e.g., core_business_owner, core_steward) |
lineDisplayTypeKey | string | Edge visual style used for ownership visualization |
Default Labels
The defaultLabels array specifies values that display as labels on diagram nodes. Each entry has a type and value:
| type | Purpose |
|---|---|
attributeTypeKey | Show an attribute value below the node name (e.g., description, classification) |
relationTypeKey | Show a relation label on edges |
userObjectRelationTypeKey | Show an ownership badge on nodes |
{
"defaultLabels": [
{ "type": "attributeTypeKey", "value": "core#description" },
{ "type": "relationTypeKey", "value": "core#has_gdpr" }
]
}
The preferred key format is FQN with hash (core#has_gdpr). Legacy formats with underscore also work but should not be used in new packages.
Layout and Path Defaults
| Property | Default | Effect |
|---|---|---|
defaultDisableAutoLayout | false | When true, auto-layout is off. Nodes stay where the user places them. |
defaultDisableShowAllPaths | false | When true, only direct connections render. Reduces visual noise in dense graphs. |
Start with defaultDisableShowAllPaths: true for complex metamodels — showing all transitive paths in a dense graph creates visual clutter.
AI Diagram Generation
The diagramGenerationPrompt property provides an AI prompt template for generating diagram layouts automatically. The prompt uses the {{currentObject}} placeholder, resolved at runtime with the object’s metadata and relations.
{
"diagramGenerationPrompt": "Generate a data lineage diagram for {{currentObject}}. Include upstream sources and downstream consumers within two hops."
}
The AI analyzes the object’s relation graph and produces a suggested layout. Users review and accept or modify the generated diagram.
diagramGenerationPrompt is available since 2025. It generates diagram layouts using AI based on object relationships.
Connecting Metamodels to Object Types
Defining a metamodel is not sufficient — each object type that should appear in diagrams needs a graphDisplayLevels array referencing the metamodel key and display level key.
{
"key": "table",
"name": "Table",
"graphDisplayLevels": [
{
"metamodelKey": "my_lineage",
"displayLevelKey": "table"
}
]
}
This bidirectional linking is required. The metamodel defines the diagram structure. The object type opts in by declaring which display level it occupies.
An object type can participate in multiple metamodels:
{
"graphDisplayLevels": [
{ "metamodelKey": "my_lineage", "displayLevelKey": "table" },
{ "metamodelKey": "core#knowledge_graph", "displayLevelKey": "core#simple_object" }
]
}
For cross-package references, use FQN: "metamodelKey": "core#data_lineage", "displayLevelKey": "core#folder".
Complete Metamodel Example
A lineage metamodel for a database connector:
{
"key": "my_lineage",
"name": "Data Lineage",
"viewTypeKey": "data_lineage",
"isDefault": true,
"displayLevels": [
{ "key": "database", "name": "Database", "displayTypeKey": "folder",
"isSingleHideable": true },
{ "key": "schema", "name": "Schema", "displayTypeKey": "folder",
"parentKey": "database", "isSingleHideable": false },
{ "key": "table", "name": "Table", "displayTypeKey": "object",
"parentKey": "schema", "isSingleHideable": false,
"objectTypes": [{"objectTypeKey": "table"}, {"objectTypeKey": "view"}] },
{ "key": "column", "name": "Column", "displayTypeKey": "column",
"parentKey": "table", "isSingleHideable": false,
"objectTypes": [{"objectTypeKey": "column"}] }
],
"relationTypes": [
{ "key": "core#hasDatasource", "lineDisplayTypeKey": "data_lineage", "isDefault": true }
],
"defaultLabels": [
{ "type": "relationTypeKey", "value": "core#has_gdpr" }
],
"defaultDisableAutoLayout": false,
"defaultDisableShowAllPaths": true,
"translations": [
{ "languageKey": "en-GB", "name": "Data Lineage" },
{ "languageKey": "cs-CZ", "name": "Datová linie" }
]
}
The corresponding object types reference this metamodel:
{ "key": "table", "graphDisplayLevels": [{ "metamodelKey": "my_lineage", "displayLevelKey": "table" }] }
{ "key": "column", "graphDisplayLevels": [{ "metamodelKey": "my_lineage", "displayLevelKey": "column" }] }
Gotchas
Missing graphDisplayLevels on an object type means the type does not appear in the diagram, even if the metamodel includes a display level for it. Both sides of the link are required.
A metamodel without relationTypes renders nodes but draws no connecting lines. The diagram appears as isolated boxes with no visible relationships.
Referencing a nonexistent relation type key does not produce an installation error. The relation type is silently ignored, and no edges render for that type. Always verify relation type keys exist in the package or its dependencies.
For conceptual_model metamodels, each lineDisplayTypeKey must have exactly one default relation type. Missing or duplicate defaults cause an installation error. Other metamodel types have no such restriction.
Set isDefault: true on the primary metamodel. Users see it first when opening the diagram tab. Non-default metamodels appear in a dropdown for secondary views.
Start with defaultDisableShowAllPaths: true for complex metamodels. Showing all transitive paths in a dense graph creates visual noise that obscures the direct connections users care about.
Before creating a new metamodel, check if the core package already defines one that fits. Most connector packages reuse core#data_lineage — only the graphDisplayLevels on object types need to be configured.