Neurocourse

Data between nodes: expressions and branches

n8n's magic is data threading: a form name lands in an email, an email amount in a condition. We master {{ }} expressions, drag-and-drop field mapping and the IF node for branching.

Nodes are the skeleton of a workflow. The data running between them is the blood. Time to learn how to steer it.

Every node hands data to the next one

Click a node that has run and you'll see its output: fields and values (name, email, amount…). The next node can use any of them.

Expressions in {{ }}

Any text field on a node takes more than plain text — it takes substitutions:

New lead from {{ $json.name }}!
Phone: {{ $json.phone }}, amount: {{ $json.amount }} €

You don't need to memorise the syntax: open the data panel on the left and drag the field you want into the text — n8n writes the expression for you. Dragging fields is skill number one in this lesson.

Forks: the IF node

The IF node splits the flow into two branches based on a condition:

[Lead form] → [IF: amount > 1000?]
  true  → [Telegram to the manager: "Big lead!"]
  false → [Just write it to the sheet]

Conditions are set up with a form: field, operator (greater than / equals / contains), value. Several conditions combine with AND/OR.

This lesson's mini-practice

Take yesterday's morning digest and add this: IF "temperature below 5°" → the message gets "Grab a jacket! 🧥" appended. Data from the HTTP node → a condition → two versions of the text. That's the template behind every workflow you'll build from here.

What $json, $node and the dot mean

Read {{ $json.name }} like this: $json is the data that arrived at this node; the dot means "go inside"; name is the field. If the data is nested, there are more dots: in the weather response the temperature sits at {{ $json.current.temperature_2m }}. And when you want a field from an earlier node rather than the one right before, there's $node:

From the node next door:  {{ $json.amount }}
From a nested field:      {{ $json.current.temperature_2m }}
From a node by name:      {{ $node["Form"].json.email }}

Again — you almost never type this, you drag it with the mouse and n8n fills in the right dotted path. But knowing what the dot means pays off: the day an expression comes back undefined, you'll see instantly that you missed a level of nesting.

IF versus Switch

The IF node gives you exactly two branches — true and false. When you need more than two (lead / complaint / question / spam), you reach for Switch — same idea, several outputs. The rule is simple: two outcomes, IF; many outcomes, Switch. We'll dig into Switch in the lesson on sorting the inbox; for now just know that forks scale.

Myths about data

  • "I have to learn expression syntax." You don't. 95% of the time you're dragging fields with the mouse. Syntax only matters for reading and lightly tweaking what's already there.
  • "Copying the value by hand comes to the same thing." It doesn't: an "Ivan" you pasted in stays "Ivan" forever, while {{ $json.name }} drops in the new customer's name on every run. An expression is alive; typed text is dead.
  • "Empty data panel means the workflow is broken." Usually it just means the node hasn't run. Hit Execute on the node before it and the data shows up, fields draggable.

Why does n8n only show draggable fields after a node has run, instead of right away? Think about it: before it runs, n8n has no idea what the form or the API will hand back — whether there'll be a "phone" field at all. The data panel shows the real result, not a guess. That's why "run it → see the actual fields → drag them" beats guessing field names blind.

When the data won't drag

Check that the node before it has run (Execute) — the data panel only shows data that genuinely passed through. Empty panel = run the node again.

The Set node: tidying your data

API data often arrives with junk fields and awkward names. The Edit Fields (Set) node is your repackager: it keeps what you need, renames it and throws out the rest, so what flows on downstream is clean and readable. For example, trimming that bulky weather response down to two fields:

Before (from HTTP):  { "current": { "temperature_2m": 3.4, "time": "...",
                       "wind_speed_10m": 12, ...a dozen more fields... } }
After (Set):         { "temp": 3.4, "city": "Berlin" }

Getting into the habit of tidying data before forks and AI nodes saves hours of debugging: when a field is called temp rather than current.temperature_2m, both your prompt and your IF condition read at a glance.

Do this now

Open yesterday's morning digest. In the Telegram node, drag the temperature field from the data panel into the message text so it reads "It's {{ $json.current.temperature_2m }}° right now". Add an IF node after the HTTP Request with the condition "temperature < 5", and in the true branch append "Grab a jacket! 🧥" to the message. Run Execute against different weather (swap the coordinates around) and make sure both branches fire.

Practice · 4 tasks

Short questions on the lesson — with an explanation for every answer.