Skip to content

How to create custom OPC UA Information Models

Last updated on March 6, 2022

More complete tutorial

This post gives you a quick introduction into creating custom OPC UA Information Models.

A more complete tutorial, including explanations how to configure your editor and the open62541 stack, and then compile your custom information model up to a fully running OPC UA server is given in:

From modelling to execution – OPC UA Information Model Tutorial

As explained in my previous post, OPC UA organizes all the nodes inside an address space:

This address space can be extended by custom information models. A Tutorial on how to create your own custom information model is described in this chapter.

Every custom information model or companion specification should be delivered as the official NodeSet2.xml format. This file contains all the nodes and references between the nodes inside this specific information model.

The goal for this tutorial is to come from a mind-model to the final NodeSet2.xml format. That file can then be used to automatically initialize an OPC UA Server which supports loading that file format.

All the files and tools used in this tutorial are also available here:

An example OPC UA Server which is using this Information model is shown here:

The basic pipeline is sketched in the following diagram:

The summarized steps are:

  1. You have an idea
  2. Then you need a tool or you manually write the Model.xml File
  3. Use the UA-ModelCompiler to convert the Model.xml file to especially the transportable NodeSet2.xml Format
  4. In addition to the NodeSet2.xml Format, the model compiler also outputs some more files which may be required by other tools
  5. Load the NodeSet2.xml file into an OPC UA Implementation which supports initialization by NodeSet2.xml files

The following sections lead you through these steps.


First the sketch

Before creating your own information model you should already have a rough idea what information this model should contain.

In this tutorial we want to create our own (simplified) companion specification for animals. This includes defining our own animal types, and even defining instances of animals.

  • Objects
    • Animals
      • Cat (Name: Cattie)
      • Dog (Name: Wuffy, Weight: 10kg)
  • ObjectTypes
    • AnimalType (Name)
      • MammalType (Legs, Sound)
        • DogType (Optional weight)
        • CatType
  • DataTypes
    • AnimalSoundType (Structure with Verb and URL to Audio file)

In our simplified world, every Animal should have a name. Every Mammal has a specific number of legs, and a sound. For the sound we define a custom datatype which represents a structure with two fields: the sound verb as per the Wikipedia article and a URL to a sound file. For a dog one can optionally also define a weight.

Modeling Best Practices

The OPC Foundation released a Whitepaper describing best practices for information modelling. It includes naming conventions and other helpful tips:

Tools to create NodeSet2.xml file

Of course you could just write the NodeSet2.xml file manually. This would be really cumbersome and may lead to invalid and inconsistent node set files. Therefore this is not recommended. Another possible solution would be to just use the provided server API and create all your nodes through the corresponding API calls. This is not a portable solution and should also be avoided.

There are various tools which can be used to create your own NodeSet2.xml file. This section gives a short overview over some of the most common open-source and commercial tools:

Unified Automation UaModeler and Free OPC UA Modeler

UaModeler is a commercial tool which offers a nice GUI to define your own custom nodeset. You can load other nodesets and extend them with your own custom types and instances.

After modeling the nodeset, you can export it to various formats, including the NodeSet2.xml format. The free version is limited to a maximum of 100 nodes.

Playing around with this tool revealed that for simple node sets, this tool can be a good starting point. If your node set involves a lot of inheritance and complex relations between nodes the UaModeler comes to its limitations. In my tests changing the base type of a node lead to invalid child nodes and a broken node set.

Another similar tool, but completely open-source, is the “Free OPC UA Modeler” ( It is currently work in progress, but the current state looks quite promising.

Beeond UMX Pro – UA Model eXcelerator ProfessionalUA Modeling eXcelerator (UMX)

The Beeond UMX Pro Tool is a graphical designing tool which can be used to design OPC UA Models similar to the UaModeler. It also adds adds code generation capability for a number of SDK’s (including Prosys Java, OPCF UANETStandard, Matrikon Flex, OPEN62541, and any other that can launch a CLI).


The OPC Foundation’s model compiler is used by various groups and by the OPC Foundation itself to create the official NodeSet2.xml files for the companion specifications. It is written in C#, but in combination with Mono, it can also be used on Linux.

The corresponding fix for mono can be found here:

This is currently the tool which is most up-to-date and supports all the required features to define a node set.

One major drawback is, that this model compiler does not provide any GUI. You have to write your own Model.xml file manually using a text editor. The UA-ModelCompiler then reads this Model.xml file, checks its consistency and integrity, and then creates the NodeSet2.xml files, including the Types.bsd definition, and NodeId.csv files.

Anyways I strongly recommend to use this approach, since it is the one which supports the most features. In the following sections I explain in more detail how to use the ModelCompiler.

Create your own Model.xml template file

As explained in the previous section, we are using the UA-ModelCompiler tool to get the final NodeSet2.xml file. The UA-ModelCompiler takes a Model.xml file as input. This file has to be manually written for your own model.

Remember, we want to create a node set for our previously presented animal model. Here is the corresponding model file as a starting point. This only includes the boilerplate template which is required for all model.xml files, and defines the Namespace URI for our own model. (See for a more detailed explanation about the Namespace URI)

Note that we already define the resulting Namespace URI in the file as

<?xml version="1.0" encoding="utf-8"?>


        <Namespace Name="animal" Prefix="animal" XmlNamespace="" XmlPrefix="animal"></Namespace>
        <Namespace Name="OpcUa" Version="1.03" PublicationDate="2013-12-02T00:00:00Z" Prefix="Opc.Ua" InternalPrefix="Opc.Ua.Server" XmlNamespace="" XmlPrefix="OpcUa"></Namespace>

    <!-- ### Reference Types ###-->

    <!-- ### Object Types ###-->

    <!-- ### Variable Types ###-->

    <!-- ### Data Types ###-->

    <!-- ### Objects ###-->


In the next steps I assume that you are extending this base model file with the corresponding code snippets.

To build your custom Model.xml file and check if you have any errors I recommend to execute the build script from time to time.

All the files used in this tutorial are available on my Github Repository:

Add your own nodes to the Model.xml

In the previous section we created the basic model.xml file which we are going to extend in this section.

If you do not know how to write a specific XML construct, you can always look into other Model.xml files, like the one for the DI specification:

DataType and VariableType

As shown at the beginning, we want to define our own data type and variables for the sound of an animal. This is achieved by first adding the AnimalSound DataType node. The base type is a ua:Structure since we define our own custom structure.

The datatype has two fields, a Verb as a String (see the Wikipedia article). Also, a AudioFile URL can be set:

    <!-- ### Data Types ###-->

    <!-- AnimalSound -->
    <DataType SymbolicName="ANIMAL:AnimalSound" BaseType="ua:Structure">
        <Description>Sound of an animal</Description>
            <Field Name="Verb" DataType="ua:String">
                <Description>Sound Verb</Description>
            <Field Name="AudioFile" DataType="ua:String">
                <Description>URL to an audio file</Description>

This part defines a custom data type, which we could already use for properties.

OPC UA defines two types of Variables: Properties, and Data Variables. A property does not allow to have subnodes, while variables can be extended an can have additional nodes as children. A more detailed explanation is given here:

In our example we want to allow subtypes to extend the animal sound variable with more custom DataVariables, e.g., loudness. Therefore we define a VariableType which is using the custom DataType:

    <!-- AnimalSoundType -->
    <VariableType SymbolicName="ANIMAL:AnimalSoundType" DataType="ANIMAL:AnimalSound" BaseType="ua:BaseDataVariableType" ValueRank="Scalar" ExposesItsChildren="true">
        <Description>Represents the sound of an animal</Description>
            <Variable SymbolicName="ANIMAL:Verb" TypeDefinition="ua:BaseDataVariableType" DataType="ua:String" ModellingRule="Mandatory">
                <Description>Verb describing the animal sound</Description>
            <Variable SymbolicName="ANIMAL:AudioFile" TypeDefinition="ua:BaseDataVariableType" DataType="ua:String" ModellingRule="Optional">
                <Description>URL to an audio file for the sound</Description>

Object Types

After defining our custom variable and data types, we add the AnimalType ObjectType node to the Model.xml file. The AnimalType should have a mandatory name property.

    <!-- ### Object Types ###-->
    <!-- AnimalType with mandatory name -->
    <ObjectType SymbolicName="ANIMAL:AnimalType" BaseType="ua:BaseObjectType" IsAbstract="true" SupportsEvents="true">
        <Description>Base type for all animals</Description>
            <Property SymbolicName="ANIMAL:Name" DataType="ua:String" ValueRank="Scalar" ModellingRule="Mandatory">
                <Description>Name of the animal</Description>

We do the same for the MammalType which is a subtype of the AnimalType and is using the AnimalSoundType variable:

    <!-- MammalType subtype of AnimalType with mandatory legs and sound -->
    <ObjectType SymbolicName="ANIMAL:MammalType" BaseType="ANIMAL:AnimalType" IsAbstract="true" SupportsEvents="true">
        <Description>Base type for all mammals</Description>
            <Property SymbolicName="ANIMAL:LegCount" DataType="ua:UInt32" ValueRank="Scalar" ModellingRule="Mandatory">
                <Description>Number of legs the animal has</Description>
            <Variable SymbolicName="ANIMAL:Sound" TypeDefinition="ANIMAL:AnimalSoundType" DataType="ANIMAL:AnimalSound" ModellingRule="Optional">
                <Description>The sound the animal makes</Description>

Next, we define the object type for cats and dogs. Note that this time the IsAbstract attribute is not set. Therefore its value is set to false by default, and these types can be used to create instances.

    <!-- CatType as a subtype of a MammalType -->
    <ObjectType SymbolicName="ANIMAL:CatType" BaseType="ANIMAL:MammalType" SupportsEvents="true">
        <Description>A cat mammal</Description>

    <!-- DogType as subtype of a MammalType -->
    <ObjectType SymbolicName="ANIMAL:DogType" BaseType="ANIMAL:MammalType" SupportsEvents="true">
        <Description>A dog mammal</Description>
            <Property SymbolicName="ANIMAL:Weight" DataType="ua:Double" ValueRank="Scalar" ModellingRule="Optional">
                <Description>Weight of the dog in KG</Description>

Object Instances

Now that we have all the base types we need, to create animals, we can start creating instances.

To collect all the instances in one place, we create a AnimalSet sub-folder under the Objects folder. This example also shows how to create references between object nodes:

    <!-- ### Objects ###-->
    <Object SymbolicName="ANIMAL:AnimalSet" TypeDefinition="ua:BaseObjectType">
        <Description>Contains all instances of animals</Description>
            <Reference IsInverse="true">

Now it’s time to create our first instance of an animal. The snipped below shows the instantiation of a CatType. This should be organized in the previously created AnimalSet folder, and have the name Cattie. Here we do not yet define the optional animal sound child.

    <Object SymbolicName="ANIMAL:Cat" TypeDefinition="ANIMAL:CatType">
        <Description>A Cat named Cattie</Description>
            <Reference IsInverse="true">
            <Property SymbolicName="ANIMAL:Name" DataType="ua:String" AccessLevel="Read">
            <Property SymbolicName="ANIMAL:LegCount" DataType="ua:UInt32" AccessLevel="Read">

Similar to the cat example, we can create a dog. This time we set the sound variable and initialize it with a default value:

    <Object SymbolicName="ANIMAL:Dog" TypeDefinition="ANIMAL:DogType">
        <Description>A dog named Wuffy</Description>
            <Reference IsInverse="true">
            <Property SymbolicName="ANIMAL:Name" DataType="ua:String" AccessLevel="Read">
            <Property SymbolicName="ANIMAL:LegCount" DataType="ua:UInt32" AccessLevel="Read">
            <Variable SymbolicName="ANIMAL:Sound"
                      ModellingRule="Mandatory" ValueRank="Scalar" AccessLevel="Read">
                <Description>Sound of the dog</Description>
                            <!-- we can not use ANIMAL:AnimalSound of the DataType here. The model compiler does not replace it.
                            Therefore we need to use the resulting node id: ns=1;i=15025-->
                            <AnimalSound xmlns="">

That’s it! The full Model.xml file can also be found here:

Creating the NodeSet2.xml file

Now that you have your own Model.xml file. There are basically two ways to compile the Model using the official OPC Foundation UA-ModelCompiler:

  • Linux: Use a precompiled docker container
  • Linux/Windows: Download the UA-ModelCompiler sources and compile the binary yourself. It’s based on .Net

If you are on Linux, I strongly recommend to use the precompiled docker container available on DockerHub:

git clone
cd opcua-animal-cs
docker run \
	  --mount type=bind,source=$(pwd),target=/model/src \
	  --entrypoint "/app/" \
	  sailavid/ua-modelcompiler:opcua_rocks_tested \
	   /model/src/animalModel animal /model/src/Published

This will build the model and copy it into opcua-animal-cs/Published/animal:

  • animal.Classes.cs
  • animal.Constants.cs
  • animal.DataTypes.cs
  • animalModel.csv
  • animalModel.xml
  • animal.NodeSet2.xml
  • animal.NodeSet.xml
  • animal.PredefinedNodes.uanodes
  • animal.PredefinedNodes.xml
  • animal.Types.xsd
  • animal.Types.bsd

To manually compile the model compiler binaries, please have a look into the corresponding Readme section:

If you have issues creating the files in the Published folder, you can also use the pre-compiled files from the example repository:

The next step is to use the generated NodeSet2.xml in any supported stack or modeler. E.g. you could open the NodeSet2.xml file using UaModeler.

The open source OPC UA Stack open62541 also supports reading NodeSet2.xml format and can initialize its address space with the predefined nodes. With this you can easily start an OPC UA server offering your custom nodeset.

A more detailed tutorial on how to achieve this will be added soon in a separate post. As a quick-start you can have a look at the prepared repository:

Published inInformation Modelingopen62541


  1. Mariusz Postol Mariusz Postol

    It is a very important workout because ModelDesign schema is used as the syntax definition of a language used to represent the UA Information Model. Each language must have also semantics definition that couples together the meaning (knowledge how to apply the text) and syntax constructs. What is the role of this document? Are you going to define the semantics of this language?
    Unfortunately, simplification is not the mother of simplicity. Someone could say that the spec is a good description of the semantics. Partially it is true, but how to learn using the spec what it means TaypeDefinition attribute for the Method element.

    Write the complete configuration of the AnalyserDevice and all of its components to the analyser server and make the new configuration active.

    BTW, please consider referring to the section of my ebook:

    Anyway, I appreciate your effort. Let me know your opinion.
    Best regards,

    • Stefan Profanter Stefan Profanter

      Thanks for your comment!
      Unfortunately I also did not find any useful documentation on the ModelDesign syntax for Model.xml.
      I’m just a user, not the developer of the UA-ModelCompiler.

      Anyways I will try to extend this tutorial (or write another post) about the syntax for the Model.xml file.

      • Michael HANSEN Michael HANSEN

        Hello Stefan

        reat posts – much appreciated. Do you have any further update on the ModelDesign syntax for Model.xml?



        • Stefan Profanter Stefan Profanter

          Thanks for reading the posts. Unfortunately I currently do not have as much time as I would like to have for writing new posts. Hopefully this will improve by mid 2020.
          In the meantime the XSD file may help you at least a bit:

  2. Juan Juan

    Nice Post! Hope you keep posting more interesting info about OPC UA!

  3. OPC UA Address Space Explained • OPC UA rocks

    […] How to create custom OPC UA Information Models […]

    • Stefan Profanter Stefan Profanter

      To instantiate an object with a specific variable type, the code looks something like this:

      <Object SymbolicName="DI:ParameterSet" ModellingRule="Mandatory">
      <Variable SymbolicName="ROB:ActualPosition" TypeDefinition="OpcUa:AnalogUnitType" DataType="OpcUa:Double" ModellingRule="Mandatory">
      <Description>The axis position inclusive Unit and RangeOfMotion.</Description>
      <Variable SymbolicName="ROB:ActualSpeed" TypeDefinition="OpcUa:AnalogUnitType" DataType="OpcUa:Double" ModellingRule="Mandatory">
      <Description>The axis speed on load side (after gear/spindle) inclusive Unit.</Description>

      An example with AnalogItemType is included here:

  4. Yogie Yogie

    Can’t wait to read custom nodeset implementation using Open62541.

  5. Ranjini Ranjini

    Is there a defined way I can initialize the UAVariable that can be subscribed to its default Value? If the Value field is used to define the constant, then there is no way to know if its default value or last instance value when the snapshot was taken. There will be no way to differentiate it. Reading your Post I understand , I can have extension elements but that is custom made. What provision is already there in UA Information Model to accommodate this?

    • Stefan Profanter Stefan Profanter

      The OPC UA specification itself does not really provide a way to know if the variable is still the default value or a newer value. You can try to use the source timestamps to see if and how the value was changed.
      Or you create a read-only variable which always holds the default value.

  6. Mariusz Postół Mariusz Postół

    CAS OPC UA Address Space Model Designer is moving to open-source

    Let me inform you that CAS OPC UA Address Space Model Designer has been just published on GitHub as the open-source OPC UA Address Space Model Designer available at

    For now, it is a stand-alone project, but any ideas related to harmonization with your needs are welcome. Further development and priorities will be derived from community feedback. The old installation package is still available on the web-page:

    I am also in the process of moving the CommServer software family to open source. The master plan is available here:

    CommServer – management of migration to open source

    Any questions, suggestions, and proposals are welcome.

  7. Marek Marek

    Why you did not mention open62541 xml nodeset compiler? I have noticed that it is generating less files, then UA-ModelCompiler, for example it do not contain header file of node ids.

    • Stefan Profanter Stefan Profanter

      The open62541 nodeset compiler is something different than the UAModelCompiler. Note that I was deeply involved in developing the XML Nodeset Compiler in open62541.

      The UAModelCompiler takes ModelDesign.xml files and “Compiles” these files into NodeSet2.xml files.
      The open62541 Nodeset Generator can NOT directly work with ModelDesign.xml files. It requires NodeSet2.xml files as input.
      Therefore a typical pipeline is:
      Manually Edit ModelDesign.xml -> Run UaModelCompiler (generates NodeSet2.xml) -> Run open62541 Nodeset Generator (generates C Source Code) -> Compile open62541

      • Marek Magáth Marek Magáth

        Thanks for clarification!

  8. Mariusz Postol Mariusz Postol

    Hi Stefan, instead of your pipeline:

    Manually Edit ModelDesign.xml -> Run UaModelCompiler (generates NodeSet2.xml) -> Run open62541 Nodeset Generator (generates C Source Code) -> Compile open62541

    Use ASMD to generate -> NodeSet2.xml -> Run open62541 Nodeset Generator (generates C Source Code) -> Compile open62541

    Consider harmonization of the open62541 code generation with ASMD. The compiler is just plugin, so it can be used even if the technology is different.

  9. Jean-Philippe Halgand Jean-Philippe Halgand

    Hello Stefan,
    Thanks for your nice example which helps a lot to start.
    In your example, there is a Variable DefaultValue, which uses ExtensionObject.
    If the data type of the variable is an ARRAY (of Int32 for instance), how should be written the uax:Body section ?
    Is there a reference help for that syntax somewhere ?

    • Stefan Profanter Stefan Profanter

      Hi Jean-Philippe,
      thanks for your comment.

      In the specific example above, the structure of the extension object is defined by AnimalSound DataType (derived from ua:Structure).
      The AnimalSound Datatype has a Verb Field, and a AudioFile Field.

      Unfortunately there isn’t really a reference help for the format. You can try to look at the XSD file here:

      If the DefaultValue is a simple datatype, i.e., Int32, then it should look like this:


      And for an array of points:

      <Point xmlns="">
      <Point xmlns="">

  10. Tom Schuettler Tom Schuettler

    Hi Stefan,

    nice post.
    Do you know if there is an automated way to generate a ModelDesign.xml file from an existing NodeSet2.xml file?

    Best regards,

  11. Arshad Usman Arshad Usman

    Hi , Is it must to use xml information model .. can’t we use Json formate , as i have embedded system

    • Stefan Profanter Stefan Profanter

      On an embedded system you typically do not need to parse XML or any other file.
      The nodeset is already converted during the compilation of the binary file (at least for the open62541 stack), and therefore it is included in the deployed binary.

      There is already a draft for a binary nodeset format, but it’s not yet officially released by the OPC Foundation.

      • Arshad Usman Arshad Usman

        @stefan .. what if I want to update my nodes from information model . I am using xml and parse it accodingly it bad idea for embedded system .

        • Stefan Profanter Stefan Profanter

          Not sure if I understood your question correctly… So you are asking, how you can update an information model on an embedded system, e.g., if the product is already released?

          In that case you will need to provide a new firmware binary which includes the updated information model.

          Otherwise, you can of course also write an XML parser, include it in your firmware and initialize the server’s node set by parsing the models on startup.

          • Usman arshad Usman arshad

            Okay .. thank you ..1 last question I am working with xml information for embedded system .
            I have also send user data which is different for each node (Adress to call a funtion ) can i send it with xml nodes.

          • Stefan Profanter Stefan Profanter

            You need to implement the read callback in your used OPC UA stack and connect the callback to the corresponding XML Node.

  12. Jan Jan

    The URL to the “OpcUaDiModel.xml” is deprecated.

    • Stefan Profanter Stefan Profanter

      Fixed. Thanks!

  13. audupi audupi

    I am trying to use the pre-compiled docker container for building Nodeset2 files.

    the docker run command, requires a xml file and a csv file for the information model created.

    I am using UA Modeler/SioME for generating the xml file, However I am not sure how to generate the required csv file for the same.

    Any suggestions would be helpful.

    • Stefan Profanter Stefan Profanter

      The UA-ModelCompiler is creating the .csv files out of the ModelDesign.xml files.

      A year ago I created a PullRequest with which the additional .csv file is not required anymore. Unfortunately I didn’t have time to fully complete it, therefore it’s still pending:

  14. Motasem Motasem

    Thanks for the article. I want to create an information model based on 4 companion specifications. Is there already an example of this?

  15. Ander Ander

    Hello Stefan,

    First of all, I’d like to thank you because all your posts about OPC UA Modeling are being really helpful for me on the development of an OPC UA server.

    I need to set role permissions on my server, so that, certain nodes are accessible only to specific roles. I know how to do it on code, but I’d like to know if it possible to do it in the model XML file.

    UAModeler from Unified Automation shows the option to specify the role permissions for the nodes. But I’d prefer to define the model in a XML file to be compiled by the UA-ModelCompiler.

    Is this even possible? In that case, could you give us any tip on how to proceed?

    Thanks for your helpful posts.

  16. Arshad Usman Arshad Usman

    Hi I am working with CAN proctocol , each CAN has certain address 0x102030 (32 bit ), I want to ask, where in information model I can give my own address, against each address I will get float value , So in node VALUE, i can put data type float but where can i give my 32 bit integer address.

  17. matf4 matf4

    Hello Stefan,
    I’m new in OPC-UA.
    How can I define a specific TypeDefinitionId for a node in the designo model?

    My code is like


    In the csv output file “MyType” take TypeDefinitionId = 1.
    I tried to use NumericId=”112233″ inside the ObjectType tag but it was useless.

    Can you help me please?
    Thank you in advance!

  18. matf4 matf4

    The code didn’t show (due to angular brackets), I try again (omitting them in the beginning and end of each row):
    ObjectType SymbolicName =”MyType” BaseType=”ua:BaseObjectType”
    Variable SymbolicName=”Value” DataType=”ua:Double” ValueRank=”Scalar” TypeDefinition=”ua:AnalogItemType” AccessLevel=”Read”/

Leave a Reply

Your email address will not be published.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.