Skip to main content
The Data Modeling Language extension (DML) offers a simplified way of building data models in CDF based on the GraphQL Schema Definition Language. A data model in the context of DML is a collection of related types representing the domain specific concepts you want to model for a given use-case. DML functions as an abstraction layer on top of the Data Modeling Service (DMS) API, when you define a data model using DML and publish it, the types and properties in your DML data model are converted into the relevant data models, views, and containers in DMS.
The data modeling REST API (DMS) in combination with the Cognite Python SDK offers more power and flexibility than the DML extension. They’re the preferred tools for managing industrial knowledge graphs in Cognite Data Fusion (CDF).

DML HTTP endpoint

Send POST requests with a JSON GraphQL payload to:
See Endpoint in GraphQL queries for {cluster}, {project}, and authentication. Use this /dml/graphql URL for DML schema work only. For instance queries and mutations, use the GraphQL URL for your data model on that same page.

Types

Types are the basic building block of your data model and represent use-case specific concepts. Each type is associated with one or more properties which are each associated with another type. Below is a simple type definition in DML modeling an Equipment type with two properties: title and pages:

Extending types via inheritance

Using GraphQL inheritance rules, you can create types that extend parent types and inherit all their properties.
  • Define a type as an interface to make it extendable.
  • Use the implements keyword to extend this base type from another type.
  • Extend multiple interfaces by separating them with an ampersand (&).
In most implementations of the GraphQL Schema Definition Language, interfaces are treated differently from types; they cannot be queried directly and serve only as blueprints to be implemented by other types.In DML, interfaces function as both types and interfaces. This means that when you change a type to an interface, the only functional difference is that it can now serve as a parent type for others. You can still query the interface via the CDF APIs as if it were still a standalone type in your data model.
Below is an example of inheritance in DML:
In this example, the parent type (Equipment) is implemented by the Pipe type, which inherits all parent properties and adds specific properties relevant only to the child type. There are some caveats with fields that are imported from inheritance, learn more in the advanced section.

Properties

A type consists of a collection of properties. Each property can be a scalar, an enum, or a reference to a custom type. When a property references a custom type, it represents a relation between instances in your data model.

List properties

By default a property can only contain a single value:
To make a list property that can contain multiple values, add brackets ([]) around the type of the property:

Limiting number of values on list properties

By default list properties can have maximum of between 100 and 1000 values depending on the property type. To override the default maximum values on a list property, use the @limits directive:

Scalar properties

Scalar properties represent primitive data.

Enum properties

Enum properties are special scalars that must match one of several predefined, distinct values. To create one, declare an enum and then use that enum as the type of another property:

CDF resource type properties

Properties can also reference non-data-modeling resource types in CDF. The value of these properties is a string reference to the external ID of the underlying resource. Using these native types enables specialized querying capabilities via the GraphQL API and some of our SDKs. Below is an example of a type having CDF native resource properties:

Relation properties

Relations allow types to reference other types, forming connections within your data model. These can point to single or multiple target instances. You create relation properties in DML by defining a property that uses a custom type as its type:
This example models a type representing a book with a relation connecting it to a single author. In DMS there are three types of relation properties:
  1. Direct relations: A container property storing a reference to another node.
  2. Edges: A connection property that can be used to describe one-to-many or many-to-many relationships.
  3. Reverse direct relation: A connection property representing a direct relation in another type going in the opposite direction.
You can read more about these in the direct relations vs. edges and the reverse direct relations sections in the data modeling documentation. The type of relation property used for a property in DML is determined by several factors described below.

Direct relations

A relation with a single target instance defaults to a direct relation:
To model a list of references using direct relations, you must add the @directRelation directive. Without this, list property will default to being modelled as an edge:

Reverse direct relations

A reverse direct relation looks “backward” through an existing direct relation on the target type. You must specify the throughProperty on the target type for the graph traversal.

Edges

Since single-target relations default to direct relations, add the @relation directive to define a single-target edge relation:
A multiple target relation property defaults to edge so in this case no @relation directive is necessary to model it as an edge:
Properties on edges
Edges can possess their own properties. To define these on an edge relation, create a type annotated with the @edge directive and link it using edgeSource in the @relation directive:
Overriding edge type
The edge type used to identify an instance of an edge defaults to {your_typename}.{your_fieldname}. However, you can override this behavior and manually specify the edge type using the type field within the @relation directive.
Overriding edge direction
The relational direction for edges defined in DML is OUTWARDS by default. To create a relation that points inwards (referencing incoming edges), add the direction argument to INWARDS on the @relation directive.

Descriptions

GraphQL descriptions are supported and will be converted to the corresponding description property on view, container and property definitions. To set the name of a view, container, or field, start a line in the description with @name followed by the name value. Example of GraphQL descriptions:

Specification of directives

The following is a list of the directive definitions, with descriptions.

Advanced: Types and their relation to DMS views and containers

Types in the DML data model are abstractions of DMS schema resources (views, containers, and data models). When you publish a DML data model in your CDF project, it’s persisted in DMS as a collection of schema objects (containers, views, and data models). Similarly, when you open an existing data model in DML, the DML schema is regenerated from the published DMS schema objects.

Containers and views

Each type in a DML data model has an equivalent view and container. The identifiers for these resources are determined by the following rules: Container identification (by space and external ID):
  • External ID: Uses the @container directive’s external ID if present, otherwise defaults to the type name.
  • Space: Uses the @container directive’s space if present, otherwise defaults to the data model’s space.
View identification (by space, external ID, and version):
  • External ID: Uses the @view directive’s external ID if present, otherwise defaults to the type name.
  • Space: Uses the @view directive’s space if present, otherwise defaults to the data model’s space.
  • Version: Uses the @view directive’s version if present, otherwise generates a version identifier based on the type definition (ensuring any changes to the type definition result in a new view version).

View and container properties

Once a type has been mapped to a view and container, its properties are also mapped to equivalent view and container properties. Each type property always has an equivalent view property in the view mapped to the type. However, which container property the view property maps to is determined by the following rules (in order of precedence):
  1. Explicit mapping: If the type property has a @mapping directive, the directive determines which container property to use.
  2. Inherited mapping: If the property is inherited from a parent type, the view property maps to the same container property as the equivalent property in the parent type.
  3. Default mapping: Otherwise, the view property maps to a container property with the same name in the container mapped to the type.
When you use the @mapping directive, the system doesn’t auto-create the referenced container property if it doesn’t exist. Only use @mapping to reference container properties that already exist.

Example DML to DMS mapping

When you publish this DML data model, it creates the following DMS resources: Equipment interface:
  • View: Created with external ID Equipment in the data model’s space (no @view directive, so it uses the type name)
  • Container: Created with external ID Equipment in the data model’s space (no @container directive, so it uses the type name)
  • Property name:
    • View property name in the Equipment view
    • Maps to container property name in the Equipment container (no @mapping directive and not inherited, so a new container property is created with the same name)
Valve type:
  • View: Created with external ID Valve2 in the data model’s space (explicitly set via @view directive)
  • Container: Created with external ID Valve in the data model’s space (no @container directive, so it uses the type name)
  • Property name:
    • View property name in the Valve2 view
    • Maps to container property name in the Equipment container (inherited from the parent Equipment interface, so it reuses the same container property as the parent)
  • Property diameter:
    • View property diameter in the Valve2 view
    • Maps to container property diameter in the Valve container (no @mapping directive and not inherited, so a new container property is created)
  • Property material:
    • View property material in the Valve2 view
    • Maps to container property material in the Valve container (no @mapping directive and not inherited, so a new container property is created)
The Valve type’s name property references the Equipment container rather than its own Valve container. This is because inherited properties always map to the same container property as their parent type.

Spaces and naming collisions

When you create multiple data models in the same space with identical type names, they will interfere with each other and cause errors. Consider this scenario where you have two data models in the same space: Data model A:
Data model B (causes collision):
When you try to publish data model B, you’ll see an error like this:
This happens because these two data models will have view properties that map to the same container property but with different requiredness. To prevent naming conflicts:
  • Use one data model per space - This eliminates the possibility of collisions.
  • Use unique type names - If you need multiple data models in the same space, ensure all type names are unique across models.
Last modified on May 5, 2026