TL;DR — OPC UA Part 17: Alias Names

Full spec: reference.opcfoundation.org/Core/Part17/v105/docs · Version 1.05.07 · Published 2026-04-15

NodeOPCUA Implementation: Part 17 support is landing in an upcoming release of NodeOPCUA — server-side Aliases / TagVariables / Topics folders, FindAlias and FindAliasVerbose, and the client-side resolve-and-failover loop described below. This page is the conceptual companion to that release.

Companion reading: Part 12 — Global Discovery Server (the "DNS + CA" that hosts the system-wide alias lookup) · ISA-5.1 tag naming vs. explicit OPC UA modelling (why aliases dissolve the naming dilemma).

What Is It?

An AliasName is DNS for your OPC UA address space. Instead of hard-coding "the temperature is ns=3;s=PLC1.DB7.Real42 on server opc.tcp://10.0.0.14:4840", you ask the system "where is TI101?" and it hands back one or more ExpandedNodeIds (NodeId + Server) — resolved at runtime, from whichever server actually holds the data today.

flowchart LR
    C["🏢 Client<br/>knows only the tag 'TI101'"]
    L["🔎 FindAlias('TI101')<br/>on a local / aggregating / GDS endpoint"]
    R["ExpandedNodeId list<br/>ns=3;s=PLC1.DB7.Real42 @ ServerB<br/>(+ redundant copy @ ServerC)"]
    N["🌡️ The actual Variable<br/>on ServerB"]
    C --> L --> R --> N
    style C fill:#1d3557,color:#fff
    style L fill:#2d6a4f,color:#fff
    style R fill:#6a040f,color:#fff
    style N fill:#333,color:#fff

The analogy is the spec's own: "analogous to the way domain names are used as an alias to IP addresses… Like a DNS Server, an OPC UA Server that supports AliasNames provides a lookup Method that will translate an AliasName to a NodeId."


The Problem It Solves

In a small system a client is configured with the exact (ServerEndpoint, NodeId) of every point it needs. That coupling breaks down the moment the system is large, distributed, or dynamic:

Pain (spec §4 use cases)Without aliasesWith aliases
Complex, multi-tool engineering (§4.1)Every config must know each tag's full address, protocol, securityEngineer against agreed names (e.g. ISA tag TI101); resolve addresses later
Automatic reconfiguration (§4.2)Config moves between servers → every client re-configuredAlias re-points; clients just re-FindAlias
Cloud / elastic servers (§4.3)Servers spin up or split by load → addresses churnName is stable; NodeId+Server resolved on demand
Tiny devices (§4.4)A simple device cannot host a lookup serviceAn aggregating server or GDS provides names on its behalf
Device replacement (§4.5)New device = new NodeIds = re-map everywhereAdd the same alias on the replacement; clients unaffected

The GDS already tells you which servers exist and how to connect (Part 12) — but historically not which tags live inside them. Part 17 fills exactly that gap.


The Information Model — Just Five Things

flowchart TD
    OBJ["Objects Folder"] --> A["📁 Aliases (well-known)<br/>AliasNameCategoryType + LastChange"]
    A --> TV["📁 TagVariables (well-known)<br/>aliases → Variables only"]
    A --> TP["📁 Topics (well-known)<br/>aliases → PublishedDataSets only"]
    TV --> AL["🏷️ AliasNameType 'TI101'<br/>BrowseName IS the alias"]
    AL -->|AliasFor| VAR["🌡️ Variable ns=3;s=..."]
    AL -.->|AliasFor redundant| VAR2["🌡️ Variable on redundant server"]
    style A fill:#2d6a4f,color:#fff
    style TV fill:#1d3557,color:#fff
    style TP fill:#1d3557,color:#fff
    style AL fill:#6a040f,color:#fff
  1. AliasNameType — an Object whose BrowseName is the alias. No properties, no value; the name carries the meaning. It has at least one AliasFor reference to the real Node(s). Rule: the BrowseName is immutable — to "rename" you delete and re-add, which mints a new NodeId, so aggregators can detect the change.
  2. AliasNameCategoryType — a FolderType subtype that groups aliases and hosts the lookup Methods. Nestable into hierarchies. Optional LastChange (VersionTime) property = cache-invalidation signal.
  3. AliasFor reference — a NonHierarchicalReferences subtype linking alias → target. Inverse name HasAlias (the target need not reference back). The target can be any NodeClass, including nodes on another server.
  4. Well-known instances (static NodeIds, so they aggregate cleanly): Aliases (root, under Objects, where LastChange is mandatory), TagVariables (aliases pointing only at Variables), Topics (aliases pointing only at PublishedDataSets — Part 14).
  5. AliasNameDataType — what a lookup returns: { AliasName: QualifiedName, ReferencedNodes: ExpandedNodeId[] }. Always at least one referenced node.

The Core Operation — FindAlias

This is 90% of what clients use. It is a plain OPC UA Call on an AliasNameCategory instance:

FindAlias(
  [in]  String  AliasNameSearchPattern,   // wildcards per Part 4 "Like" operator, e.g. "TI1%"
  [in]  NodeId  ReferenceTypeFilter,      // AliasFor or a subtype; restricts by ReferenceType
  [out] AliasNameDataType[] AliasNodeList // ordered best-match-first
);

Key semantics that clients must handle:

  • A search returns a list, and each alias can reference a list of nodes. The same tag may live on several servers (redundancy, aggregation). "Clients should use the first usable entry" — the server orders them by preference (health, load-balancing, off-loading small devices). Fall through to the next on failure.
  • Wildcards follow Part 4's Like FilterOperator — %, _, [ ]. "TI1%" finds TI101, TI102, and so on.
  • The alias namespace is ignored for comparison — a client compares alias strings, never (ns, name) pairs.
  • Resolve the server: when the call went to a GDS or aggregating server, read the target's ServerUri / ServerArray to turn the ExpandedNodeId into a real connection. That is the last hop before a normal browse, read, or subscribe.

FindAliasVerbose — same call, richer answer

An optional extension returning AliasNameVerboseDataType, which adds ServerUris[] (per referenced node) and AliasNameCategoryId — so you do not need a second round-trip to learn which server and which category each hit came from.

Configuration methods (optional facet)

  • AddAliasesToCategory(names[], targetNodes[], targetServers[], refType) — parallel arrays; a name repeated N times maps to N targets. Targets may be on remote servers, and the server need not verify their existence (Uncertain_ReferenceOutOfServer).
  • DeleteAliasesFromCategory(names[], targetNodes[]) — can only delete aliases defined locally. An aggregator cannot delete aliases it merely pulled from an upstream server.

The Four Deployment Topologies

This is where the practical value lives — the same client code (FindAlias → connect → use) works against all four:

flowchart TB
    subgraph one["A · Inside one Server"]
        direction TB
        S1["Server hosts both the Aliases folder<br/>and its own Variables"]
    end
    subgraph agg["B · Aggregating Server"]
        direction LR
        AG["Aggregator<br/>aliases point at nodes<br/>in other servers"]
        AG --> U1["Server 1"]
        AG --> U2["Server 2"]
    end
    subgraph stand["C · Standalone Alias Server"]
        direction LR
        ST["Pure lookup box, owns no data<br/>for devices too small to host aliases"]
        ST --> D1["Device A"]
        ST --> D2["Device B"]
    end
    subgraph gds["D · GDS — auto-aggregating"]
        direction LR
        G["GDS at a well-known endpoint<br/>merges aliases from every server<br/>exposing the 'Alias' capability"]
        G --> R1["Server X"]
        G --> R2["Server Y"]
    end

    one ~~~ agg ~~~ stand ~~~ gds

    style one fill:#1d3557,color:#fff
    style agg fill:#1d3557,color:#fff
    style stand fill:#1d3557,color:#fff
    style gds fill:#2d6a4f,color:#fff
  • A · Single server — the server names its own tags. The simplest case.
  • B · Aggregating serverAliasFor targets live in other servers; the aggregator may return the underlying node or a replicated copy in its own address space.
  • C · Standalone alias server — owns no process data at all; a pure directory for devices that cannot host aliases themselves, or for retro-fitting names onto already-deployed servers.
  • D · GDS — the big one. A GDS that supports aliases automatically merges the TagVariables and Topics of every server registering with the Alias capability into one master tree at a well-known endpoint. This is the system-wide DNS: a client points at one address and resolves any tag anywhere.

GDS Behaviour (Annex C) — Why It Is the Payoff

The GDS turns aliases from a per-server convenience into a network-wide service. Required automatic behaviour:

EventGDS doesClient impact
Server registers (C.2)Merges its aliases into the master list; identical alias names from different servers are combined (multiple ExpandedNodeIds under one name); adds its ServerUri to ServerArrayNew tags appear automatically
Server unregisters (C.3)Removes that server's aliases and AliasFor refs; keeps an alias alive if other servers still back it; drops the ServerUriStale entries clean themselves up
Client ↔ server link fails (C.4)Client returns to the GDS and requests a fresh AliasNodeList for the tagBuilt-in failover: pick the next ExpandedNodeId — no reconfiguration

Redundancy falls out for free: a sensor wired to two servers publishes TI101 from both → the GDS reports two ExpandedNodeIds → the client fails over between them.

Push or pull? Who initiates?

The single most-asked question. The answer: alias data always moves by PULL; only the trigger can be a push, and even then the push carries no alias content.

flowchart LR
    S["🖥️ Alias-capable Server"] -->|"1 · Push: RegisterServer2 (Part 12)<br/>'I exist + Alias capability'"| G["🌐 GDS / Aggregator"]
    S -.->|"2 · Signal only: LastChange tick<br/>(subscribe = pull · Annex D multicast = push)"| G
    G ==>|"3 · PULL: Browse the Aliases folder<br/>→ read the actual alias nodes"| S
    style S fill:#6a040f,color:#fff
    style G fill:#2d6a4f,color:#fff
TriggerDirectionWhat crosses the wireGDS then…
Registration (C.2)Push — server RegisterServer2 advertises the Alias capability"I exist and have aliases"pulls the whole alias tree once
LastChange subscribe/pollPull — GDS holds a session, subscribes to each AliasNameCategory.LastChangea VersionTime tickpulls the changed category
PubSub multicast (Annex D, provisional)Push — server Publishes, GDS Subscribesonly {categoryId, LastChange}no alias contentpulls (browses) the flagged category

So the model is push-to-notify, pull-to-fetch: the notification only says "category X changed at T, come look"; the GDS always browses to get the actual aliases. Because all aliases sit under the mandatory Aliases folder, that browse is trivial. The PubSub option exists purely for scale — holding a LastChange subscription to thousands of servers means thousands of sessions; a fire-and-forget multicast heartbeat avoids that.


Resync, Collisions and Lifecycle

Resync keys entirely off the persisted LastChange:

  • Newer than cache → browse and diff that category. Index 0 of every frame is the root Aliases, whose LastChange rolls up all children — an unchanged root means you can skip everything.
  • Older than cache (server reset or rollback) → discard the entire cached subtree and re-browse from scratch.
  • Missed messages self-heal: PubSub is best-effort, so a delta frame can be lost — periodic key frames carry the full state and correct it. Never rely on deltas alone.
  • Liveness: no keep-alive for a configurable timeout → the GDS drops all of that server's aliases; a frame with a new ApplicationUri → auto-discover a new server.

Collisions are merges, not conflicts — the same name on many servers is the redundancy feature, not an error:

  • Same alias on servers B and C → one alias name, multiple ExpandedNodeIds; FindAlias orders them best-first and the client fails over. Namespace is ignored when comparing alias names.
  • Categories merge on the matching Name part of the BrowseName. Well-known categories have static NodeIds so they merge cleanly; a locally-namespaced category cannot be proven identical, so the GDS may keep two instances under different namespaces.
  • Exact duplicates (same alias, target, and server) are silently ignored.
  • Unregister is collision-aware: an alias or category backed by several servers survives until the last backing server unregisters; otherwise only that server's AliasFor reference and ServerUri are pruned.
  • Deletion asymmetry: a GDS or aggregator cannot delete aliases it pulled upstream (DeleteAliasesFromCategoryBad_InvalidState); they vanish only when the owning server drops them and the next resync notices.

The spec is deliberately loose about lifecycle: re-read cadence and GDS persistence are implementation choices, not normative.

How often does the GDS re-read? Event-driven, never on a fixed clock. Re-reads are triggered by a server (re-)registering (registration is itself periodic under Part 12, so it doubles as a heartbeat), a LastChange tick if subscribed, a PubSub frame (Annex D), or an optional periodic full reconciliation as a backstop. Each trigger causes a targeted browse of the flagged category — not a blind full re-pull.

Server up and down:

  • Clean shutdown → unregister → prune (the alias survives if other servers still back it).
  • Crash, no goodbye → detected via registration lapse (Part 12) or keep-alive timeout (Annex D). Until then FindAlias may hand out the dead node — client-side C.4 failover absorbs it. Stale entries are tolerated by design.
  • Recovery → re-register → re-pull; the persisted LastChange decides incremental diff versus full flush.

GDS persistence — split aliases in two. Aliases pulled from upstream are a cache: the source of truth is each owning server, so on restart the GDS re-registers everyone and re-pulls; persistence is only an optimisation. Aliases owned locally (created via AddAliasesToCategory) make the GDS the source of truth, so it must persist those. While the GDS is down only resolution stops — owning servers are unaffected. The real mitigation for the single point of failure is a redundant GDS, not disk.

Does the GDS need a live subscription to every server? No — and that is the point. Serving a FindAlias needs no connection to the target at all: it returns ExpandedNodeId + ServerUri from cache, and the client connects.

ModelStanding GDS↔server connectionFit
PubSub multicast (Annex D)None — connectionless notify; transient browse only on changeThousands of servers; best-effort, key-frame self-heal
LastChange subscriptionOne session per serverReliable; does not scale to thousands
Poll on re-registrationTransient — connect, browse, dropCoarse freshness, zero standing sessions

Keeping Aggregators Fresh — LastChange and the PubSub Extension

An aggregator or GDS must know when an upstream server's aliases changed. Two mechanisms:

  • Polling LastChange — each AliasNameCategory (mandatorily the root Aliases) carries a LastChange VersionTime. Subscribe to it; if the value you read is older than your cache, flush the whole cached subtree and re-browse. It works, but one session per upstream server does not scale to thousands.
  • PubSub multicast notification (Annex D, provisional) — an opt-in extension where each alias-capable server becomes a tiny Publisher on a configurable multicast address, with a fixed DataSetClassId (65880051-7e5b-4a96-ae47-e0ef4704b924). It emits key frames (the full array of category LastChange timestamps, index 0 always the root Aliases), delta frames (only changed categories) and keep-alives (whose absence auto-removes the server, and whose new ApplicationUri auto-discovers a new one). Because delivery is not guaranteed, aggregators must not rely on delta frames alone. Annex D is explicitly marked as having limited implementation and may see breaking changes.

Security and Access Control — Anonymous or Protected?

Part 17 defines no alias-specific security model. Aliases are ordinary Nodes and Methods, so they inherit the full OPC UA security stack — and whether they are reachable anonymously is a server configuration choice, not something the spec fixes. The spec neither mandates protection nor forbids open access; it does anticipate access control by giving every alias Method a Bad_UserAccessDenied result code. See also Part 18 — Role-Based Security.

Three independent layers decide who gets what:

LayerGovernsCan it be anonymous / open?
Session / transportEndpoint SecurityPolicy + MessageSecurityMode (None/Sign/SignAndEncrypt) + user token (Anonymous / UserName / Certificate)Yes — a server may expose an anonymous SecurityMode=None endpoint that answers FindAlias, or require an authenticated, encrypted session
AuthorizationRolePermissions / UserRolePermissions / AccessRestrictions on the alias Nodes (Part 3)The server's choice — read (FindAlias) and write (Add/Delete) are gated independently
The target nodeThe target server's own security, applied when you actually Read or SubscribeIndependent — resolving an alias yields only a NodeId + ServerUri, never a value

The critical point: an alias lookup returns an address, not data. Exposing FindAlias broadly does not expose the values behind it — the target node stays protected by its own server's security. This is exactly why treating FindAlias like public DNS is often reasonable.

Practical stance:

  • FindAlias / FindAliasVerbose (read) — often safe to expose broadly, even anonymously, since it leaks only addresses. But tag names themselves can be reconnaissance-sensitive — decide per deployment.
  • AddAliasesToCategory / DeleteAliasesFromCategory (write) — restrict to engineering roles; these mutate the directory.
  • GDS endpoints — secured per Part 12; the GDS authenticates to registered servers and to clients at its well-known endpoint.
  • PubSub notification (Annex D)SecurityMode is configurable (None / Sign / SignAndEncrypt) with a SecurityGroupId and an SKS (Part 14); a signing-only header layout exists precisely for integrity without encryption on the multicast channel.

⚠️ Because nothing in Part 17 mandates protection, an implementer can leave aliases wide open or lock them down. Treat alias exposure as a deliberate security decision, not a default.


Practical Client Recipe

The whole point is that this loop is address-independent:

1. Decide your lookup endpoint (config): local server | aggregating server | GDS.
2. Call FindAlias("TI101", AliasFor)  ->  AliasNameDataType[].
3. Take the first entry; take its first ReferencedNode (ExpandedNodeId).
4. Resolve its ServerUri via the ServerArray  ->  real endpoint.
5. Connect (reuse the session if it is the same server) -> Browse/Read/Subscribe as normal.
6. On failure: fall through to the next ReferencedNode / next alias entry,
   or re-call FindAlias on the GDS for a fresh list (Annex C.4 failover).

Gotchas worth internalising:

  • Never assume one result. Both the alias list and each alias's node list can have more than one entry. Design for it up front.
  • Aliases are immutable strings. A "rename" is delete-then-add and yields a new NodeId for the alias node — do not cache alias NodeIds as identity; cache the name.
  • TagVariables vs Topics are typed: TagVariables resolve to Variables (client/server read and subscribe), Topics resolve to PublishedDataSets (PubSub configuration). Pick the right category for what you are wiring.
  • Ignore the alias's namespace when matching names.
  • LastChange is your cache key. Older-than-cached means purge and re-browse.
  • Deletion is local-only. An aggregator or GDS cannot delete upstream-owned aliases.

Where Part 17 Sits

It gives youIt does not give you
A name → NodeId (+Server) lookup (FindAlias)Any change to how you read or subscribe once resolved — it is normal OPC UA after that
A standard place (Aliases / TagVariables / Topics) to publish namesA mandated nomenclature — ISA TI101 is just an example; naming is your (or a companion spec's) choice
System-wide resolution via GDS aggregationA replacement for GDS discovery and certificates (Part 12) — it complements them
Redundancy and failover as a natural consequenceGuaranteed delivery of change events (the PubSub path is best-effort)

Bottom line: Part 17 decouples what a client wants ("give me TI101") from where it currently lives. In a static two-node setup it is overkill; in a large, redundant, cloud-elastic, or multi-vendor plant it is the difference between reconfiguring every client when anything moves — and not.


Official References

Specification (OPC Foundation online reference, v1.05):

Conformance units (profiles.opcfoundation.org):

Nomenclature note: the TI101 example tag follows ANSI/ISA-5.1, Instrumentation Symbols and Identification — Part 17 references it only as an illustration and mandates no naming scheme of its own. For the design argument behind that, read the companion piece: ISA-5.1 tag naming vs. explicit OPC UA modelling.


TL;DR generated from OPC 10000-17 v1.05.07 (2026-04-15). For normative wording, including exact result codes, conformance units, and table definitions, always consult the official specification.