DataTypeDefinition
In OPC UA, DataTypeDefinition is the attribute on a DataType node that describes a server-defined structure, union or enumeration field by field. Introduced in 1.04, it lets a client decode custom types at runtime without a compiled stub or the legacy binary type dictionary. It holds a StructureDefinition or an EnumDefinition.
What the attribute contains
Read the DataTypeDefinition attribute of a DataType node and you get one of two structures. A StructureDefinition carries the DefaultEncodingId, the BaseDataType, a StructureType discriminator and an array of StructureField entries - each with Name, DataType, ValueRank, ArrayDimensions, MaxStringLength, IsOptional and a description. An EnumDefinition carries an array of EnumField entries with Value, Name and DisplayName. That is enough information to build a decoder at runtime for anything the server can send.
The StructureType discriminator
StructureType tells the decoder which encoding rules apply: Structure for a plain sequence of fields, StructureWithOptionalFields when a leading bit mask selects which optional fields are present, Union when a leading switch value selects exactly one field, and the subtyped-value variants where a field may carry any subtype of its declared DataType. Ignoring this field is the single most common way a hand-written decoder produces garbage rather than an error.
How a client uses it
The standard sequence is: read the Variable's DataType attribute, resolve that DataType node, read its DataTypeDefinition, follow HasEncoding to the Default Binary or Default JSON encoding node, and build the decoder keyed on that encoding NodeId - because the encoding NodeId, not the DataType NodeId, is what arrives in the ExtensionObject on the wire. Mature stacks wrap this: asyncua exposes load_data_type_definitions() on the client, and the .NET reference stack builds complex-type descriptions the same way.
Generating it rather than writing it
In a nodeset the attribute appears as a Definition element inside the UADataType, with one Field per member and IsOptional or IsUnion where relevant. UA-ModelCompiler emits it, and has a -useAllowSubtypes switch precisely because subtype-permitting fields otherwise degrade to plain ExtensionObject. If you author models by hand, generating the nodeset with the ModelCompiler is the reliable way to get the definition, the encoding nodes and the identifier CSV consistent with each other.
Example
A structure with an optional field, as it appears in a nodeset and as the attribute reads back
<UADataType NodeId="ns=1;i=3002" BrowseName="1:RecipeStep">
<DisplayName>RecipeStep</DisplayName>
<References>
<Reference ReferenceType="HasSubtype" IsForward="false">i=22</Reference>
<Reference ReferenceType="HasEncoding">ns=1;i=5002</Reference>
</References>
<Definition Name="1:RecipeStep">
<Field Name="StepNumber" DataType="i=7"/>
<Field Name="Setpoint" DataType="i=11"/>
<Field Name="Comment" DataType="i=21" IsOptional="true"/>
</Definition>
</UADataType>
<!-- ns=1;i=5002 is the "Default Binary" encoding node.
It is this NodeId that appears in the ExtensionObject on the wire. -->
<!-- Reading the DataTypeDefinition attribute of ns=1;i=3002 returns:
StructureDefinition
DefaultEncodingId = ns=1;i=5002
BaseDataType = i=22 (Structure)
StructureType = StructureWithOptionalFields
Fields
[0] StepNumber UInt32 IsOptional=false
[1] Setpoint Double IsOptional=false
[2] Comment LocalizedText IsOptional=true -->
Defined in: Part 3 - Address Space Model defines the DataTypeDefinition attribute, StructureDefinition and EnumDefinition; Part 6 - Mappings defines the encodings they describe.
Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.