November 11, 2025
November 11, 2025

Digital Twin Definition Language (DTDL) provides a standardized way to create virtual representations of physical objects, processes, and systems. This comprehensive tutorial explains DTDL concepts, metamodel classes, and demonstrates building a complete digital twin model of a bottling plant with visualization.
Understanding DTDL is essential for architects and developers implementing digital twin solutions using Azure Digital Twins or other platforms supporting this open standard.
A digital twin is a virtual representation of a physical object, process, or system—a car, airplane, building, temperature sensor, factory, or production process. Digital twins enable monitoring, simulation, and optimization of physical assets through their digital counterparts.
To create digital descriptions of physical assets and systems in a standardized manner, Microsoft developed and open-sourced the Digital Twin Definition Language (DTDL).
DTDL uses a variant of JSON called JSON-LD (JSON Linked Data). JSON-LD is powerful because it allows linking data within JSON objects to express semantics inherent in the data.
Consider a JSON object describing a pressure sensor on a filling machine. The JSON object would have data linking to another JSON object describing the filling machine on which the sensor is installed.
Consequently, the JSON object describing the filling machine would link to the bottling line in which the machine is located. This allows hopping from data point to data point, linking related information together—hence "linked data."
Using JSON-LD, DTDL provides a standardized way of digitally describing not only the structure and attributes of physical entities but also the relationships between them.
DTDL defines seven primary metamodel classes—digital templates describing the structure and rules for representing different types of elements associated with physical entities:
Let's explore each metamodel class with examples.
The Property class enables representing elements that don't change frequently or don't change at all.
Here's how to define a serial number property element for a filling machine using JSON-LD:
json
{
"@type": "Property",
"name": "serialNumber",
"schema": "string"
}
@type: Identifies the kind of information being described (Property)
name: User-defined name of the element
schema: Data type of the element—can be primitive types (integer, double, string, boolean) or complex data types
Properties can be read-only or read-write. A serial number would be read-only, while an operating speed property could also be written to for adjusting speed.
Properties require a storage mechanism that retains data permanently and allows updates as needed.
The Telemetry class enables describing data emitted by a physical entity—typically a stream of sensor readings or occasional alerts and information messages.
Here's how to define a flow rate telemetry element for a filling machine:
json
{
"@type": "Telemetry",
"name": "flowRate",
"schema": "double"
}
Unlike properties, telemetry isn't stored on a digital twin. It's processed as it arrives and sent to external systems if needed.
The Command class enables describing functions or operations that can be performed by a physical entity. Commands can take inputs and return responses.
Here's an example command specifying an instruction to start filling at a specified time:
json
{
"@type": "Command",
"name": "startFilling",
"request": {
"name": "startTime",
"schema": "dateTime"
},
"response": {
"name": "scheduledTime",
"schema": "dateTime"
}
}
The command returns the scheduled filling time as a response.
The Relationship class enables describing how physical entities are linked together.
For example, a bottling line would be related to a filling machine in that the bottling line contains the filling machine. A filling machine would be related to a capping machine in that the filler supplies bottles to the capper.
Connecting digital twins via relationships creates a twin graph (sometimes called a knowledge graph) representing physical entities in your entire environment while reflecting their interactions.
Here's a relationship element for a bottling line digital model showing the line has a filler:
json
{
"@type": "Relationship",
"name": "hasFiller",
"target": "dtmi:com:example:FillingMachine;1"
}
The name represents the semantic meaning of the relationship, and the unique identifier of the related target model can be specified.
Relationships can be defined with or without specific targets. Sometimes you might define a relationship without a target so it can connect to many different types of twins.
The Component class enables describing models that are components of other models.
For example, a filling machine may have a camera as its component. You'd first define the camera as a standalone model, then reference it when defining the filling machine.
What criteria determine whether something is a component or a separate related model?
Use a component to describe something that is an integral part of your solution but doesn't need a separate identity and doesn't need to be reflected in the twin graph independently.
If you want your motor to have an independent existence in the twin graph, represent it as a separate digital model and connect it to the filling machine using relationships.
Here's an example showing how a camera would be referenced as a component within a filling machine digital model:
json
{
"@type": "Component",
"name": "camera",
"schema": "dtmi:com:example:Camera;1"
}
The schema references the camera model using its unique identifier.
The Interface class encloses all elements of a digital twin model. It allows describing all elements that make up a complete digital model.
For example, an interface of a bottling line model would specify:
The interface is the top-level object of a DTDL definition—what you start with when defining a digital twin model. Then you add other objects inside it.
Here's an example interface of a filling machine digital model:
json
{
"@context": "dtmi:dtdl:context;3",
"@id": "dtmi:com:example:FillingMachine;1",
"@type": "Interface",
"displayName": "Filling Machine",
"contents": [
{
"@type": "Property",
"name": "operatingSpeed",
"schema": "double"
},
{
"@type": "Telemetry",
"name": "pressure",
"schema": "double"
}
]
}
@context: Attaches a JSON-LD context to the JSON object so it can be processed as JSON-LD. The value is a URI pointing to the DTDL context document (version 3 in this case).
@id: The digital twin model identifier—provides a globally unique identifier for the model so it can be interacted with across different applications, systems, and platforms.
A digital twin model identifier has three components: scheme, path, and version. Scheme and path are separated by a colon, while path and version are separated by a semicolon.
@type: Indicates the element type within a model (Interface in this case).
displayName: User-friendly name for the interface.
contents: Array enclosing all elements or capabilities of the digital model.
Suppose you have a special filling machine with a temperature telemetry element in addition to pressure and operating speed elements. To express specialization, DTDL supports inheritance where interfaces can inherit from one or more other interfaces.
Add an extends field to the model:
json
{
"@context": "dtmi:dtdl:context;3",
"@id": "dtmi:com:example:SpecialFillingMachine;1",
"@type": "Interface",
"extends": "dtmi:com:example:FillingMachine;1",
"contents": [
{
"@type": "Telemetry",
"name": "temperature",
"schema": "double"
}
]
}
This special filling machine extends the filling machine interface and adds a temperature element. It inherits all attributes from the base model.
The schema for property and telemetry attributes can be standard primitive types (integer, double, string, boolean) or complex data types (array, enum, object, map).
An array describes an indexable data type where each element has the same schema. You could use an array schema for the operating speed property to capture the last five speeds set:
json
{
"@type": "Property",
"name": "operatingSpeedHistory",
"schema": {
"@type": "Array",
"elementSchema": "double"
}
}
Enum describes a data type with a set of named labels that map to values. For example, an operating mode property with predefined modes:
json
{
"@type": "Property",
"name": "operatingMode",
"schema": {
"@type": "Enum",
"valueSchema": "string",
"enumValues": [
{
"name": "automatic",
"enumValue": "auto"
},
{
"name": "manual",
"enumValue": "manual"
}
]
}
}
Object describes a data type comprising named fields with values of specific schemas. This allows creating complex structured data:
json
{
"@type": "Property",
"name": "location",
"schema": {
"@type": "Object",
"fields": [
{
"name": "latitude",
"schema": "double"
},
{
"name": "longitude",
"schema": "double"
}
]
}
}
Map describes a data type of key-value pairs where keys are strings and values conform to a specific schema. Maps are useful for flexible, dynamic data structures.
To demonstrate building a complete model, let's create a digital twin model of a bottling plant with multiple interconnected components.
The bottling plant consists of:
First, create models for each component, starting with the simplest:
Pressure Sensor Model:
json
{
"@id": "dtmi:com:example:PressureSensor;1",
"@type": "Interface",
"displayName": "Pressure Sensor",
"contents": [
{
"@type": "Telemetry",
"name": "pressure",
"schema": "double"
},
{
"@type": "Property",
"name": "calibrationDate",
"schema": "date"
}
]
}
Filling Machine Model (using components and relationships):
json
{
"@id": "dtmi:com:example:FillingMachine;1",
"@type": "Interface",
"displayName": "Filling Machine",
"contents": [
{
"@type": "Component",
"name": "pressureSensor",
"schema": "dtmi:com:example:PressureSensor;1"
},
{
"@type": "Property",
"name": "operatingSpeed",
"schema": "double"
},
{
"@type": "Command",
"name": "startFilling"
},
{
"@type": "Relationship",
"name": "suppliesBottlesTo"
}
]
}
Bottling Line Model (composing the plant):
json
{
"@id": "dtmi:com:example:BottlingLine;1",
"@type": "Interface",
"displayName": "Bottling Line",
"contents": [
{
"@type": "Relationship",
"name": "contains",
"target": "dtmi:com:example:FillingMachine;1"
},
{
"@type": "Relationship",
"name": "contains",
"target": "dtmi:com:example:CappingMachine;1"
}
]
}
Once models are created and twin instances are established, you can visualize the twin graph showing relationships between physical entities.
Tools like Azure Digital Twins Explorer provide graphical visualization where:
This visualization helps understand complex system architectures and trace data flows through interconnected equipment.
A crucial aspect of DTDL is the ability to perform queries against digital twins using SQL-like syntax. This provides a powerful way to generate advanced analytics for digital twins.
Example queries:
Find all filling machines:
sql
SELECT * FROM digitaltwins
WHERE IS_OF_MODEL('dtmi:com:example:FillingMachine;1')
Find all machines on a specific line:
sql
SELECT machine FROM digitaltwins line
JOIN machine RELATED line.contains
WHERE line.$dtId = 'line_01'
Find machines with specific property values:
sql
SELECT * FROM digitaltwins
WHERE operatingSpeed > 100
This querying capability has potential for many applications in manufacturing and other industries—identifying equipment needing maintenance, analyzing production patterns, or optimizing resource allocation.
Digital Twin Definition Language (DTDL) provides a standardized, open framework for creating digital representations of physical assets and systems. Using JSON-LD as its foundation, DTDL defines seven metamodel classes that enable expressing properties, telemetry, commands, components, relationships, and complex data types.
The Interface class serves as the container for complete digital models, supporting inheritance for specialization. Complex data types including arrays, enums, objects, and maps enable modeling sophisticated system attributes.
By building interconnected digital twin models following DTDL specifications, organizations create twin graphs that mirror physical environments, enabling monitoring, simulation, optimization, and advanced analytics through SQL-based queries. This standardization ensures interoperability across platforms and applications, accelerating digital transformation initiatives.