Ignition UDT Editor
A VS Code extension for browsing and editing Inductive Automation Ignition
UDT / tag JSON exports as a hierarchical tag tree, like the Designer's Tag
Browser and Tag Editor.
This is an independent project. It is not affiliated with, endorsed by or
sponsored by Inductive Automation. Ignition is a trademark of Inductive
Automation.
Why use it
Ignition tag and UDT exports are large JSON files that are hard to read and risky to hand-edit. This extension gives you the Designer's Tag Browser inside VS Code, so you can:
- See the structure at a glance instead of scrolling thousands of lines of JSON.
- Understand inheritance: every instance shows the members it gets from its UDT definition, with
{parameter} bindings resolved, so you can see what a tag will actually do.
- Edit safely: change properties in a familiar Designer-style sheet. Only the values you change are written, so the rest of the file stays byte-for-byte identical and your git diffs stay small and reviewable.
- Work offline and in version control: no Gateway or Designer needed, no network requests, no telemetry. Fits a code-review and git workflow for tag changes.
Requires VS Code 1.85 or newer.

What's new in 1.1.0
| Change |
How it helps |
| Designer-style property sheet with sections that match the Designer (Basic, Meta Data, Value, Numeric, Security, Scripting, Alarms, History, Custom) |
Find and edit any property where you expect it, with enums as dropdowns. |
| Alarm editor: add and delete whole alarms, nested alarm properties, override alarm lists on inherited tags |
Manage alarms across many tags without hand-editing JSON. |
| Read / Write Permissions editor (one security level per line) |
Review and change tag security quickly. |
| Editable Parameters table with per-row revert, and editing of bound parameter values |
Maintain UDT parameters in a table, and undo a change with one click. |
| Searchable Parent Data Type dropdown of the definitions found in your types folder |
Re-parent a UDT without typing a path from memory. |
| Rename propagation: after renaming a definition member you are offered to rename the matching overrides in instance files |
Avoid orphaned overrides when a UDT member changes. Nothing changes unless you confirm. |
| Designer-style tree columns (Definition, Data Type) showing a definition's parent type, flag icons and a tree filter box |
Spot alarms, history, scripts and scaling at a glance and find tags fast. |
| Ctrl+S / Ctrl+Z / Ctrl+Y for staged edits, and open folders, selection and scroll kept after saving |
Edit many tags in a row without losing your place. |
typeId lookup when there is no _types_ folder, with a fallback to the first workspace _types_ folder |
Inheritance resolves even for a loose export or a folder with a different name. |
| Fixes: a path-search loop on paths with no leading slash, the unsaved state after resetting an alarm override, and clipped or truncated alarm and new-property rows |
A more stable, less surprising editor. |

Staged edits: nothing touches the file until you press Save, and Discard drops them.

A UDT definition shows its Parameters table and Parent Data Type dropdown.
Quick start
- Install the extension and open a folder containing your tag export or UDT JSON files.
- Right-click a
.json file and choose Ignition: Open in UDT Editor.
- Click a tag to see and edit its properties. Press Save (Ctrl+S) to write only your changes.
- If your UDT definitions are not found automatically, set
ignitionUdtTree.typesRoot (see Settings).
Usage
- View a file: right-click a
.json in the Explorer or an editor tab and choose
Ignition: Open in UDT Editor, or click the structure icon in the editor title bar.
Ignition: Open UDT JSON File in Editor does the same from a file picker.
- Browse folders: the Ignition UDT Editor activity-bar view (Tag Files) lists
the tag folders you add with Ignition: Add Tag Folder. Remove or refresh
them from the view toolbar.
- The tree opens in its own editor tab, one per source file. Reopening a file
reveals the existing tab. It refreshes on save and on external changes
(for example
git checkout).
Privacy
The extension reads and writes only the JSON files you open and the definition
files they reference. It makes no network requests and collects no telemetry.
The webview runs under a strict Content Security Policy with no network access.
Settings
| Setting |
Purpose |
ignitionUdtTree.typesRoot |
The folder holding UDT definitions (the _types_ folder), absolute or relative to the workspace folder. If empty, a _types_ folder in the file's path or the nearest parent folder is used; a definition not found there is located from its typeId. |
The tree
Laid out like the Designer's browser: Definition (or Tag) and Data Type
columns, with flag icons beside each name for alarms, history, event scripts,
scale mode, read-only and disabled tags. For a UDT definition the Data Type
column shows its parent type.
Shows UDT definitions, folders, UDT instances and atomic tags, with
type-aware icons and descriptions (an OPC / Memory / Reference chip,
→ DefinitionTypeId, folder item counts). Addresses are left out of the rows
but still searched by the filter and shown in the tooltip. Data types use the Designer's names
(Integer, Short, Float, Double, Byte, Long) while the file keeps Ignition's
tokens (Int4, Float4, …).
Click a node to open the JSON beside the tree and select its "name" entry.
Duplicate names are told apart by occurrence index (the Nth match in the document).
The ‹ button on the toolbar collapses the tab to a narrow tree, hiding the
properties panel, and › restores it. Selection, scroll position and expanded
branches are kept.
Inheritance resolution
Instances, and members of a definition, store only their overrides of the
definition named by typeId. The extension locates the _types_ folder (see
typesRoot above), loads the definitions, merges the overrides and substitutes
{parameter} bindings through the chain. Inherited members show in italic with
an "Inherited from: …" tooltip, and clicking one reveals the nearest real
ancestor in the file. If no types folder is found, or a typeId is missing,
the tree falls back to the flat, unresolved view.
The tree's tooltip shows the resolved address. The properties panel always
shows and writes the literal text (still containing {device}), so a save never
bakes a resolved value over a parameterized binding.
Properties panel
Selecting a tag opens a Designer-style panel: one scrolling sheet with collapsible
sections (Basic, Meta Data, Value, Numeric, Security, Scripting, Alarms, History,
Custom). Every property Ignition writes is shown, including custom
properties such as SparkplugDeviceId. Enums are dropdowns, and an unrecognized
value is kept as an option rather than dropped.
- Overrides: a filled dot means this file overrides the parent UDT (or
Ignition's default, when the parent has no value) with a different value. A
hollow dot means it doesn't, and a node with no parent never shows one. Editing
a hollow row writes an override, and ↺ on a filled row deletes it.
- Bound properties (
{"bindType": "parameter", "binding": "…"}) show a 🔗
and just the binding text. Edits write inside the wrapper.
- Layout: a compact two-column property grid with section bars, and a
Categories list below the tree (All Properties, Basic, Meta Data, Value,
Numeric, Security, Scripting, Alarms, History, Custom). Alarms use a list of
Name - Mode, Priority entries with add and delete buttons, and the selected
alarm's grouped properties nested under the Alarms section.
- Value source and scale mode decide which rows show: Expression adds
Execution Mode (and Rate for Fixed Rate), Reference adds Source Tag Path,
Derived adds Source Tag Path and Read/Write Expression, and Linear scaling adds
Clamp Mode while Exp Filter adds Scale Factor.
- Staged edits: changes mark the tag with "●" and nothing touches the file
until Save (Ctrl+S), which writes only the changed
values and leaves the rest of the file byte-for-byte alone. Discard drops
them, and Ctrl+Z / Ctrl+Y undo and
redo staged changes (typing inside a text box keeps its own undo). After a save
the open folders, selection and scroll position are kept.
- Rename from the Name row. The name is validated live: not blank, no
characters Ignition rejects in tag paths, and no case-insensitive sibling
duplicate.
- Filter: the toolbar search box (Ctrl+F focuses it) hides rows that don't match, by name or the
chips after it (type, data type, address). Ancestors of a match stay open
and Esc clears it.
- Create: hover a folder or UDT definition and click +. Choose a name and
tag type, plus a data type and value source (atomic tags) or a
typeId (UDT
instances). New tags are staged in italic with a "new" marker.
- Delete: hover a row and click 🗑 or press Delete. The row is
struck through until Save, and 🗑 again restores it. Deleting a folder
removes everything inside it. Roots and inherited members can't be deleted.
- Custom properties are added with an explicit type (Number, String, Boolean,
Array, Document, Dataset), so a String holding
"123" stays a string. Names
can't be blank, start with __, or collide with a built-in or structural key.
- Scripts and alarms: tag event scripts are editable per event, and alarm
properties are editable on the tag that declares the alarm. Whole alarms can be
added (name box under the list) or deleted (🗑 on the alarm).
- UDT definitions show only Basic (Name, Parent Data Type), Meta Data
(Documentation, Tooltip, Type Color), Parameters and Custom. Parameters is
an editable table (name, data type, value) with add, delete and a per-row revert;
the whole
parameters block is rewritten on save, and a bound value is edited
as text inside its binding. Parent Data Type is a type-to-filter list of the definitions
found in the types folder.
- Renaming a definition member offers, after the save, to rename the matching
overrides in the instance files (found by
typeId across the workspace), since
instances attach overrides by name. Nothing is changed unless you choose Update.
- Read / Write Permissions are edited as one security level per line
(
Roles/Administrator); a value in any other shape stays as raw JSON, and
emptying the box removes the key.
- Folders show Name, Documentation and Tooltip, plus Custom, because
Ignition keeps no other configuration on a folder.
- Inherited members show their full property sheet too. Editing one writes an
override into the file: the member is added under the nearest node in this file
as
{"name": …, "tagType": …} plus the changed value, with any inherited
folders above it added the same way, as Ignition stores instance overrides.
Inherited members can't be renamed or deleted. Their address can be overridden;
for alarms, overriding, adding or deleting one writes a local override of the whole list.
Supported JSON
- A single tag or UDT object (
{ "tagType": "UdtType", "tags": [...] }).
- An array of tag objects.
- A provider/folder wrapper with a top-level
tags array (a full export or tags.json).
tagType: UdtType, UdtInstance, Folder, AtomicTag, Provider.
valueSource: opc, memory, expr, db, reference, derived (inferred from
opcItemPath / expression when absent).
Development
The source is TypeScript in src/, compiled to out/ (which is what VS Code loads).
Requires Node 20 or newer (.nvmrc pins 20; nvm use picks it up).
npm install
npm run compile # or: npm run watch
npm test # runs against out/, so compile first
npx @vscode/vsce package # builds the .vsix
Press F5 to launch an Extension Development Host, open a folder of UDT JSON
files and run Ignition: Open in UDT Editor.
| File |
Responsibility |
src/extension.ts |
Activation, commands, sidebar, file watchers, reveal-in-editor, writing staged edits back with jsonc-parser. |
src/resolver.ts |
Types-folder lookup, typeId inheritance, override merging, parameter substitution, JSON paths for edits. |
src/parser.ts |
Tag JSON to display nodes, and source offsets for reveal. |
src/properties.ts |
Declarative property schema (keys, labels, categories, editor kinds, defaults). |
src/webview.ts |
The webview panel: tree and properties HTML, icons, and the edit messaging. |
src/folderTree.ts |
The Tag Files sidebar provider. |
test/ |
node --test suites for the resolver, the save path, the parser and the webview (run under jsdom with a stubbed vscode). |
Known limitations
- Inherited members can't be renamed or deleted here.
- Definitions are found through the
typesRoot setting or a _types_ folder
above the file, or else by searching for the instance's typeId path (above
the file, then in the workspace), so the folder needn't be called _types_.
With several projects sharing typeIds in one workspace, set typesRoot.
- Saved overrides follow the shape Ignition writes in tag exports, but the
extension has not been verified against every Ignition version. The keys behind
the value-source and scale-mode rows (
executionMode, executionRate,
sourceTagPath, deriveExpressionGetter / Setter, clampMode,
scaleFactor) and typeColor have not been checked against a real export.
- Parameters are edited for UDT definitions only.
- Type Color is a plain text box, not a colour picker.
- The permissions editor keeps a level's existing match type (
AnyOf / AllOf)
and can't change it, and it assumes levels are selected as leaves of the tree.
Not implemented
- Moving or reordering members. Adding a member to a UDT instance is also
unsupported, since it would orphan the override.
- Propagating a rename of the definition itself (its typeId is its file path, so
rename the file and fix the instances). Member renames are propagated.
- Overriding a single alarm property from an instance is deliberately blocked.
- Editing DB value sources (the sheet says so).
- Summary rows with a pencil for Scripting and Alarms, and a binding button on
every property, as in the Designer.
| |