Skip to content

Nodes, Wires, and Messages

Scope: the vocabulary everything else uses — the families of nodes, what a wire really promises, and the message object opened up, with the lab's whole-message debug output as the specimen.

The families

Nodes sort into three roles:

  • Inputs start messages: inject (a button, or a schedule), http in (a web request arrived), mqtt in (a message on a topic), file in, and many more from the palette and the community library.
  • Processing nodes change, route, or judge messages: function (JavaScript), change (set or move properties without code), switch (route by rules), split and join (take arrays apart and put them back), template, delay, and friends.
  • Outputs finish the job: debug, http response, mqtt out, file (write), and the wider world's nodes.

A wire promises only this: when a node sends a message, a copy travels to every node wired from that output, in parallel. There is no queue and no memory in a wire; order between branches is not guaranteed. Most beginner surprises live in that sentence.

The message

Everything travels as one JavaScript object named msg. The lab pressed an inject button wired to a debug node set to complete message object, and the log kept the specimen (transcript t01-t08-tests.log):

{
  _msgid: '81c002c326361d4d',
  payload: 'hello from the inject node',
  topic: 'greeting'
}

Three properties do nearly all the work, across every node in this guide:

Property What it holds
msg.payload the point of the message: a string, a number, a parsed JSON object, whatever the last node put there
msg.topic a label, often the route the message took — MQTT's topic, or one you set yourself
msg._msgid Node-RED's own tracking stamp; you read it, you never set it

Nodes are allowed to add more — an http in node adds msg.req and msg.res (the request and response), a file in adds msg.filename — and the convention is that a node documents what it adds and otherwise leaves the parcel alone. When in doubt, debug the whole message, not just the payload: chapter 3's debug node has a setting for exactly that, and it is the difference between guessing and looking.

A word about payloads and types

msg.payload has no fixed type, and that is both the freedom and the trap. An mqtt in node can hand you a string, a parsed object, or a raw buffer depending on its settings; a file in can give you one long string or a stream of chunks. Flows that work in the editor and fail in the world usually fail here: a node downstream expected an object and got a string. The json node converts between the two, deliberately; automatic conversions elsewhere are conveniences to verify, not to trust.