In OPC UA, everything a server exposes - a variable, an object, a data type, a method - is a node, and each node is addressed by a NodeId. A NodeId is not just a number; it combines a namespace index that says which catalog the identifier belongs to with the identifier itself, which can be a number, a string, or a few other forms. This guide explains how a NodeId is put together, how it differs from a flat Modbus register, and how a client uses one to read a specific wellhead value out of a server's address space.
OPC UA Node ID in one line: An OPC UA NodeId is the unique address of a single node in a server's address space. It has two parts: a namespace index, which selects which namespace the identifier lives in, and an identifier, which is usually a string (shown as s=) or an integer (shown as i=). A NodeId such as ns=2;s=Pump1.RunStatus points a client at exactly one variable so it can read its value, subscribe to changes, or write to it - the NodeId is the handle for every operation on that node.
A NodeId is written in two pieces because OPC UA lets many independent naming schemes coexist on one server. The namespace index, shown as ns=, chooses which namespace an identifier belongs to. Namespace index 0 is reserved for the OPC Foundation's own base definitions, and vendor or application namespaces get higher indexes such as 1, 2, and up. The same identifier value can appear in two different namespaces and mean two different nodes, so the namespace index is what disambiguates them - the identifier alone is not enough.
The second piece is the identifier, and OPC UA supports several types. The most common are string identifiers, shown with s= and often mirroring a controller's tag path such as ns=2;s=Pump1.RunStatus, and numeric identifiers, shown with i= as in ns=0;i=2258 for a standard node. There are also GUID identifiers for globally unique keys and opaque byte-string identifiers for servers that use binary keys internally. Which type a server uses is its own choice; a client simply has to reference the NodeId exactly as the server defines it, character for character.
One subtlety that trips up integrators is that the namespace index is not guaranteed to be permanent across servers or even across restarts of some servers, because it is just a position in the server's namespace array. What is stable is the namespace URI - the full unique name of the namespace. Careful clients read the server's namespace table, find the URI they care about, and learn its current index rather than hard-coding ns=2, so that a server that reorders its namespaces does not break every reference. The identifier within a namespace, by contrast, is meant to be stable.
A Modbus register is a bare number in a flat table - address 40021, say - with no built-in name, data type, units, or context. To use it you need an external map telling you that 40021 holds a wellhead pressure as a 16-bit integer scaled by ten. The register address is purely a location; all meaning lives outside the protocol in a document you maintain by hand. There is exactly one flat space of registers, and any structure is a convention you impose on top of it.
A NodeId is fundamentally different because it addresses a node in a structured, self-describing address space rather than a cell in a flat table. The node the NodeId points to carries its own metadata: a display name, a data type, and attributes describing whether it is readable, writable, or historized. A string NodeId like ns=2;s=Well12.Casing.Pressure often reads like a path through the plant's structure, and the client can ask the server what data type and units that node has rather than relying on an external spreadsheet. The address and the description travel together.
This is why OPC UA integration feels less like decoding and more like browsing. With Modbus you start from a register list and hope it is accurate; with OPC UA you can navigate the server's address space, find the node you want, note its NodeId, and confirm its type from the server itself. The NodeId is still an address you ultimately reference explicitly - it is the durable handle you store and reuse - but it is an address into a labeled, typed model rather than into an anonymous grid of registers.
To read a value, a client issues a request naming the NodeId and the attribute it wants - typically the Value attribute of a variable node. If the client wants the current casing pressure at well 12, it references ns=2;s=Well12.Casing.Pressure and asks for that node's value; the server returns the value together with a quality status and a source timestamp indicating when the reading was taken. Rather than repeatedly reading, a client more often creates a subscription on that NodeId so the server pushes changes, but every such operation still begins by identifying the node through its NodeId.
Because the NodeId is the handle for all of this, obtaining it correctly is the crux of setting up any read. A client either browses the server's address space to discover the NodeId of the point it needs, or it is given the NodeId in the server's documentation. Once captured, that NodeId is stored in the client's configuration and reused for every subsequent read, write, or subscription - it is the persistent reference that ties the client's logical tag to the server's physical variable.
For a cloud SCADA such as Merobix connecting to an OPC UA server at a facility, NodeIds are how field values become platform tags. Merobix browses the server, resolves the namespace URI to its current index so references stay valid, and records the NodeId for each variable it needs - a wellhead pressure, a separator level, a pump status. From then on those NodeIds carry the live values, with their server-supplied quality and timestamps, into trends and alarms in the browser. Storing the namespace URI rather than a hard-coded index, and keeping the NodeId list under configuration control as the facility grows, is what keeps the connection robust when a server is upgraded or its address space is reorganized.
The ns= part is the namespace index, which selects which namespace the identifier belongs to, and the s= part is a string identifier within that namespace. So ns=2;s=Pump1.RunStatus means the string identifier Pump1.RunStatus in namespace index 2. Numeric identifiers use i= instead of s=, as in ns=0;i=2258.
No. The namespace index is just a position in a particular server's namespace array and can differ between servers, so ns=2 on one server may not correspond to ns=2 on another. What is stable is the namespace URI, the full unique name of the namespace. Robust clients look up the URI in the server's namespace table to learn its current index rather than hard-coding the number.
A Modbus register is a bare number in a flat table with no built-in type, name, or units, so you need an external map to interpret it. A NodeId addresses a node in a structured, self-describing model, and that node carries its own data type, display name, and attributes. The client can ask the server about a node instead of relying entirely on a separate spreadsheet.
This page references the protocol specifications published by the organizations below. Editions, product capabilities, and documentation change over time - confirm current requirements and specifications directly with the source.
Last reviewed: July 27, 2026. Merobix is not affiliated with, endorsed by, or sponsored by these organizations; their names are used only to identify the standards and products discussed.
Merobix reads your field devices into a cloud SCADA - the real thing behind these terms, live in days from any browser.