TL;DR:

  • Sparkplug B is an open specification (Eclipse Foundation) that standardises topic namespaces, protobuf payload encoding, and birth/death certificate session management on top of MQTT 3.1.1
  • It solves the interoperability problem of raw MQTT: without Sparkplug, every device vendor and every SCADA integrator invents their own topic structure and payload format
  • Sparkplug is widely supported in industrial platforms (Ignition SCADA, HiveMQ, EMQX) and is the most practical path to consistent IIoT data integration without adopting OPC UA

If you’ve deployed MQTT in an industrial setting, you’ve probably encountered the interoperability problem. MQTT itself specifies nothing about how to organise topics or what to put in payloads. You end up with devices publishing to /factory/line1/temp in one format, /sensors/building-a/sensor-42 in another, some using JSON, some using raw binary, and no consistent way for a SCADA host to know whether a device is online or has gone silent.

Sparkplug B is the answer the industry settled on. It’s not a new transport — it runs on top of MQTT. It’s a specification for what you publish, where you publish it, and how you manage session state. The Eclipse Foundation took over stewardship from Cirrus Link Solutions in 2022, and Sparkplug 3.0 was published as an open standard.

The Topic Namespace

Sparkplug defines a strict topic hierarchy:

spBv1.0/{group_id}/{message_type}/{edge_node_id}/{device_id}

Where:

  • spBv1.0 is the namespace identifier (fixed)
  • group_id is a logical grouping of edge nodes (e.g., manufacturing, site-chicago)
  • message_type is one of the defined Sparkplug message types (see below)
  • edge_node_id identifies the edge node (gateway or device running the Sparkplug agent)
  • device_id is optional — edge nodes can publish directly, or proxy for connected devices

Example topics:

spBv1.0/Plant-A/NBIRTH/Gateway-01
spBv1.0/Plant-A/DDATA/Gateway-01/PLC-Line1
spBv1.0/Plant-A/DCMD/Gateway-01/PLC-Line1

This consistent structure means a SCADA host subscribing to spBv1.0/# gets all Sparkplug traffic and can immediately parse which group, node, and device each message belongs to — without custom configuration per device.

Message Types

Sparkplug defines eight message types, each with a specific role:

TypeDirectionPurpose
NBIRTHNode → HostEdge node comes online; publishes complete metric list with current values
NDEATHNode → HostEdge node going offline (sent via MQTT Will mechanism)
DBIRTHNode → HostDevice comes online; publishes its metric list
DDEATHNode → HostDevice going offline
NDATANode → HostEdge node metric updates (changed values only)
DDATANode → HostDevice metric updates (changed values only)
NCMDHost → NodeCommands from host to edge node
DCMDHost → NodeCommands from host to device (relayed via edge node)

The BIRTH/DEATH pattern is the key innovation. When an edge node connects, it immediately publishes an NBIRTH message containing every metric it monitors with current values and metadata (metric name, data type, timestamp, engineering units). The SCADA host gets a complete picture of the device’s data model upfront, rather than having to infer it from subsequent data messages.

NDEATH messages use MQTT’s Last Will and Testament — the broker publishes NDEATH automatically if the edge node disconnects unexpectedly. The host always knows which nodes are live.

Payload Format: Protocol Buffers

Sparkplug payloads use Google Protocol Buffers (protobuf) rather than JSON. This is a deliberate choice for industrial settings where:

  • Bandwidth may be constrained (cellular IoT, satellite links)
  • Message frequency may be high (100ms scan rates on fast process lines)
  • Parsing efficiency matters (high-volume historians)

A Sparkplug payload contains a Payload protobuf message with a metrics array. Each metric has a name, value, timestamp, and data type:

// Simplified Sparkplug Payload structure
message Payload {
  optional uint64 timestamp = 1;
  repeated Metric metrics = 2;
  optional uint64 seq = 3;
  optional string uuid = 4;
  optional bytes body = 5;
}

message Metric {
  optional string name = 1;
  optional uint64 alias = 2;
  optional uint64 timestamp = 3;
  optional uint32 datatype = 4;
  optional bool is_historical = 5;
  optional bool is_transient = 6;
  optional bool is_null = 7;
  // ... value fields for each data type
}

In practice you use a Sparkplug library rather than writing protobuf directly. Available libraries cover Java, Python, C/C++, JavaScript, Go, and C#.

Report by Exception

Sparkplug uses report-by-exception (RBE) for data updates — NDATA and DDATA messages only contain metrics whose values have changed since the last publish. This is efficient for industrial scenarios where most values are stable most of the time.

The BIRTH message provides the baseline. Subsequent data messages carry only deltas. The host reconstructs the current state by applying each update to its cached copy of the last known values.

This design dramatically reduces MQTT broker load and network bandwidth compared to polling-style or periodic publish-all approaches.

Primary Connectors

In the Sparkplug architecture there’s a defined role called the Primary Host Application (PHA) — the SCADA or historian system that manages session state for all edge nodes. The PHA publishes a special STATE message to signal it’s online:

spBv1.0/STATE/primary-host-id

Edge nodes monitor this topic. If the PHA goes offline and comes back up, edge nodes detect the reconnection and re-send BIRTH messages to resynchronise state. This ensures the SCADA always has consistent current state even after restarts.

When to Use Sparkplug B

Good fit:

  • New IIoT deployments where you’re choosing the data layer from scratch
  • Multi-vendor device environments where you need consistent data structures across different manufacturers
  • Projects integrating with SCADA platforms that have native Sparkplug support (Ignition with the Sparkplug module is the most common)
  • Replacing ad-hoc MQTT deployments that have become unmaintainable due to inconsistent topic structures

Consider OPC UA instead when:

  • You’re integrating with existing OPC UA-native devices (PLCs, historians that already speak UA)
  • You need the full OPC UA information model for complex asset hierarchies
  • Your environment has IT/OT convergence requirements that favour the OPC UA security model

Consider raw MQTT when:

  • You’re building a simple, self-contained IoT system with a single team controlling all devices and the server
  • The overhead of the Sparkplug specification (BIRTH messages, protobuf dependencies) outweighs the interoperability benefit

Getting Started

The Eclipse Foundation hosts the Sparkplug specification and reference implementations. For SCADA integration, Inductive Automation’s Ignition platform with the Sparkplug module is the most production-tested path. For broker infrastructure, HiveMQ and EMQX both have Sparkplug-aware broker extensions that can enforce the topic namespace and surface node state in their management consoles.

Client-side, sparkplug-client for Node.js and eclipse-tahu for Python/Java are the reference implementations used in most integrations.