Using UDTs to Enforce Structure in PLC Programs

This engineering brief introduces the UDT as a foundational element to PLC program organization. It is the key to binding DB memory to function and function blocks. This is not an academic exercise, but a necessary path from merely coding a PLC to system architecture. It’s a way out of the time sink of unorganized tags.


This article is part of the DigiKey Field Guide for Industrial Automation

Location: Program It → Data Structures (UDT/DB)
Difficulty: :classical_building: System Integrator — difficulty levels explained
Author: Aaron Dahlen | MSEE | Senior Applications Engineer, DigiKey
Last update: 06 Mar 2026


What is a UDT

A UDT is an authoritative description of the shape of our data. This may be as simple as a single Boolean or as complex as an array of structs.

While the UDT is often described as a blueprint, I prefer to think of it in hardware terms. The UDT is like a physical connector specification describing what program elements can and cannot be connected together. Blocks built with the same UDT specification may easily be connected. Mismatched cables are a compile-time error.

The UDT is an undervalued tool for PLC programming. If we apply UDT-centric thinking to PLC programming, structure becomes consistent. Instead of thinking in terms of a loose collection of PLC tags we think in terms of structures and the relational integrity between program elements. The UDT is the contractual “cable specification” that describes how memory and program blocks fit together.

When is a UDT used?

The UDT is used when we construct Program Organizational Units (POUs) including databases (DBs), functions, and function blocks.

  • Database: When applied to a DB, the UDT describes the memory structure. This is done by instantiating the UDT within the DB.

  • Function and Function Blocks: When applied to a FC or FB, the UDT describes the shape of the block’s interface which then accepts the DB.

When taken together, the UDT is a linking mechanism at the block interface level. Blocks that are bound to the UDT via their respective InOut interface are seamlessly connected to each other via the DB. This binding is strictly enforced by the compiler.

The UDT is a Contract with the Programmer

The UDT is a contract defined by the programmer and enforced by the compiler. From the programmer’s perspective the contract involves:

  • Self: The programmer is making a promise to define all tag interaction at the interface level. This is an explicit rejection of the sideways tag smuggling where it is all too easy to pull a random global tag into the block.

  • Future programmers and technicians: If the original programmer is using UDTs at the block InOut interface, future programmers and technicians shouldn’t need to dig into the program. Instead, they can examine the blocks in the DB debug window.

If the DB is the singular unit of truth for the block, then the DB itself serves as a form of HMI. This thought extends to the trace tool as shown in Figure 1. Once again, we notice the dot notation used to naturally describe the tags e.g., "DB_IO_REMOTE".IO_Remote.Out.xCR1

The fastest way to breach this contract is to smuggle hidden global variables into the individual blocks.

Figure 1: DB tags inspected using the trace tool.

The UDT is a Contract with OEMs

Equipment vendors often provide PLC code. An example is a library to operate an IO-Link device. The OEMs lean heavily on the UDT. A typical “library” includes the UDT along with blocks reliant on the UDT. We are often asked to construct a DB and the conduit between the OEM’s blocks.

What is the shape of a UDT?

The UDT is often hierarchical with data elements contained within structs. An example is included as Figure 2 where a UDT describes a PLC’s local I/O. Note that In and Out structs are used to naturally group the data.

The UDTs can be nested. This is beneficial when many similar field devices are controlled e.g., 10 identical motors. Each motor’s data can be stored in indexed arrays of structures.

In all cases, tags move from loosely floating names to a strong organization where function is defined in relationship to the body of the UDT. This is best understood by the dot notation implicit in tag names. As an example, consider the input switch from Figure 2. From within your program, it is gracefully referred to as #IO_Local.In.xSW1.

Figure 2: UDT encapsulation of a PLC’s I/O.

What are the alternatives to a UDT?

Never forget the UDT influences design at the DB level and at the block interface level. The UDT is a shortcut to ensure the POUs interface correctly. The UDT explains what the system is, not just how it behaves.

Sure, all UDT functionality can be performed manually at the DB level with corresponding mapping at the program interface level. However, the UDT’s singular truth is lost as the programmer must now structure each POU independently. Stated another way, a change in one must be carefully replicated in all; happy debugging! As opposed to the singular change in UDT. Consequently, I will argue that there are no scalable alternatives to the UDT if singular truth is to be maintained across all POUs.

Note, this does not eliminate programmer frustration as a change in UDT may require modification to all the POUs touched by the UDT. However, this does not change the fact that the UDT is a singular point of truth within the system to which all blocks must conform. In practice, we modify the blocks and then instantiate them starting at Main [OB1] and working down through the program hierarchy.

There is another “alternative” which consists of a sideways smuggling of global PLC tags. In practice, this is too painful past a certain point. Encapsulation is broken and dependencies are hidden. We spend too much time digging through POUs.

Resist the temptation to use global variables.

Don’t do it!

Next Steps

  • Bind your local I/O: Refer to this article for a guide exploring local I/O and distributed I/O using an ET 200SP.

  • Impact on a running plant: Some things may be changed on the fly, while others cannot. Adding a new limit switch is complex as the UDT-based binding touches many blocks. Instead of happy green circles, we end up with blue and orange circles. That’s a complete download which translates to real dollars in terms of line downtime.

  • Style guide: Technicians looking to %I0.0 will be frustrated as tags are set within a DB abstraction layer. Construct a style guide (roadmap) document for the PLC. It should include instructions to look for I/O in places such as DB_IO-LOCAL.

:books: Continue Exploring Industrial Control Systems

If this discussion was helpful, you may also want to explore:

:world_map: DigiKey Navigation

:japanese_symbol_for_beginner: Related Foundational Articles

About This Author

Aaron Dahlen, LCDR USCG (Ret.), is a Senior Applications Engineer at DigiKey in Thief River Falls. His background in electronics and industrial automation was shaped by a 27-year military career as both technician and engineer, followed by over a decade of teaching.

Dahlen holds an MSEE from Minnesota State University, Mankato. He has taught in an ABET-accredited electrical engineering program, served as coordinator of an electronic engineering technology program, and instructed military technicians in component-level repair.

Today, he has returned to his home in northern Minnesota, completing a decades-long journey that began with a search for capacitors. Read his story here.