n8n Workflows Explained: How They Work and How to Build One
By Rick Kennerknecht, NoCode Guide
October 20, 2026

Last verified: October 2026
n8n workflows are chains of nodes that start with a trigger, pass data between nodes as a list of items, and produce one execution each time they run in production. Understand four things (triggers, nodes, items and executions) and every workflow you open, build or import makes sense. The rest is deciding what to connect to what.
This post is the anatomy lesson. If you want finished workflows to copy, the n8n workflow examples post has those. Here I want to explain what you are looking at when you open the canvas, because most beginner mistakes come from a wrong mental model, not a wrong setting.
What an n8n workflow is made of
Open any workflow and you see four kinds of thing.
A trigger. The first node. It decides when the workflow runs: on a schedule, when a webhook receives a request, when a polling node finds new data, when another workflow calls it, or when you click the run button. One workflow can have several triggers, but it needs at least one. Since n8n 2.0 the old Start node is gone; a Manual Trigger takes its place.
Nodes. Everything after the trigger. Integration nodes talk to a service (Slack, Google Sheets, a database). Core nodes shape data and control flow: IF, Switch, Merge, Loop Over Items, Edit Fields, Code, HTTP Request. There is no practical limit on how many you chain.
Connections. The wires. Data only moves along a wire, and a node only runs when something upstream sends it data. A node with no incoming connection never executes.
Executions. One recorded run of the workflow, from trigger to last node. The execution list is where you see what each node received and returned, which is the single most useful debugging tool n8n has.
How n8n workflows work: items, not rows
The thing that trips up people coming from Zapier is that n8n does not pass one record at a time. Every node receives an array of items and returns an array of items. Each item is a JSON object, optionally with binary data attached.
So if a Google Sheets node reads 200 rows, it outputs 200 items. The next node runs once and processes all 200. An IF node sorts those 200 into a true branch and a false branch. A Slack node with 50 items on its input sends 50 messages. You did not write a loop; the loop is implied.
This is why expressions look the way they do. {{ $json.email }} means "the email field of the current item". When a node runs over 200 items, that expression resolves 200 times. If you want the email from a specific earlier node, you reach back with {{ $('Read Sheet').item.json.email }}, and n8n pairs items by position.
Three consequences follow:
- If a node outputs zero items, everything after it stops. No error, just silence. Check the execution log before assuming a bug.
- If you need one summary instead of 200 messages, you aggregate first. The Aggregate node or a Code node collapses items into one.
- Loop Over Items exists for the cases where the service you are calling cannot take a batch, or where you need to pause between calls to respect a rate limit.
A minimal workflow looks like this in JSON. Paste it into a new workflow with the menu option Import from Clipboard and you will see the shape: a nodes array and a connections object keyed by node name.
{
"name": "Minimal example",
"nodes": [
{
"parameters": { "rule": { "interval": [ { "field": "minutes", "minutesInterval": 15 } ] } },
"name": "Every 15 minutes",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [0, 0]
},
{
"parameters": { "url": "https://api.github.com/repos/n8n-io/n8n/releases/latest", "options": {} },
"name": "Fetch latest release",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [260, 0]
},
{
"parameters": {
"assignments": { "assignments": [ { "name": "version", "value": "={{ $json.tag_name }}", "type": "string" } ] },
"options": {}
},
"name": "Keep only the tag",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [520, 0]
}
],
"connections": {
"Every 15 minutes": { "main": [[ { "node": "Fetch latest release", "type": "main", "index": 0 } ]] },
"Fetch latest release": { "main": [[ { "node": "Keep only the tag", "type": "main", "index": 0 } ]] }
}
}
Every workflow you will ever export has that same skeleton, just longer.
Manual runs vs production executions
There are two ways a workflow runs, and they are treated differently in the editor and on the bill.
A manual run is you pressing the run button in the editor. The workflow executes once, right now, and you watch the data flow through each node. Nothing needs to be published. These runs are how you build.
A production execution is the workflow running on its own because its trigger fired: the schedule ticked, a webhook was called, a polling trigger found a new record. These only happen after you publish the workflow.
n8n's own definition, from its pricing page, is that an execution is a single run of your entire workflow, however many steps it has. Only production executions count against a Cloud plan. Manual runs in the editor do not. Polling triggers count only when they find new data, so a Sheets trigger that checks every minute and finds nothing costs nothing.
| How the run started | Needs publishing? | Counts as a billable execution? |
|---|---|---|
| Run button in the editor | No | No |
| Schedule Trigger fires | Yes | Yes |
| Webhook receives a request | Yes (production URL) | Yes |
| Polling trigger finds new items | Yes | Yes, only when it finds something |
| Polling trigger finds nothing | Yes | No |
| Error Trigger fires | No (error workflows run when called) | Yes |
The arithmetic matters more than people expect. A workflow on a five-minute schedule runs 288 times a day, about 8,640 times a month, which is more than three Starter plans' worth on Cloud by itself. A webhook-triggered workflow that fires once per form submission might run 40 times a month. Same tool, two hundred times the cost difference. The n8n cost calculator does this sum for you across Cloud plans and a VPS; the n8n pricing page has the plan limits in EUR.
Self-hosting removes the per-execution ceiling entirely. The trade is that you own the server. That is the whole argument of self-hosting n8n, and it starts with execution math.
Publishing n8n workflows (what used to be "activating")
Until version 2.0 the switch in the top right was labelled Active, and everyone said "activate the workflow". The 2.0 breaking changes replaced the toggle with Publish and Unpublish buttons. Older tutorials still say activate; it is the same action.
Publishing does three things. It registers the trigger with the server so the schedule starts ticking or the webhook starts listening. It switches webhook nodes from their test URL to their production URL (these are different; a very common first-week bug is calling the test URL from a real system). And it starts recording executions.
Things to know before you press it:
- A published workflow with a Schedule Trigger starts running immediately on its next interval. If the interval is one minute, you have about a minute to notice a mistake.
- Saving and publishing are now separate. You can save edits to a published workflow without those edits going live until you publish again. That is a real improvement over 1.x, where a save on an active workflow took effect at once.
- Unpublishing stops triggers but keeps the execution history.
Webhook workflows deserve one more note. The production URL is the one you give to the outside service. If you are setting one up for the first time, the n8n webhooks guide walks through test versus production URLs and the response modes.
n8n workflow automation patterns worth knowing
Almost every n8n workflow automation I have built falls into one of four shapes. Recognising the shape tells you which nodes you need before you drag anything.
Sync. Trigger on new or changed records in A, transform, upsert into B. Schedule or polling trigger, one or two Edit Fields nodes, a write node. The hard part is deduplication: use the service's own ID as the match key, never the row number. A Sheets-to-CRM sync is the classic; the Google Sheets integration page covers the append versus update choice.
Alert. Schedule trigger, fetch something, IF it crosses a threshold, send a message. Add an Aggregate node if you want one digest rather than a message per item.
Intake. Webhook trigger, validate, route with Switch, write and reply. The response node at the end matters: without it the caller waits for the whole workflow to finish.
Enrich. Loop Over Items, call an API per item, merge the result back. This is the shape where rate limits and Retry On Fail earn their keep.
Whatever the shape, add the error layer before you publish. The n8n error handling post covers retries, error outputs and the Error Trigger workflow; the short version is that a workflow without an error workflow fails silently.
Versioning n8n workflows with export
n8n Cloud plans keep a few days of workflow history you can roll back to. Whatever your setup, the safe habit is the same: export the JSON and keep it somewhere versioned.
From the editor, the workflow menu offers Download, which saves the JSON file. For a whole instance, the CLI does it in one go. On a Docker install:
docker exec n8n n8n export:workflow --all --output=/home/node/.n8n/backups/
# then copy out of the container and commit
docker cp n8n:/home/node/.n8n/backups ./n8n-backups
cd n8n-backups && git add . && git commit -m "n8n workflows $(date +%F)"
A few rules that make exports useful rather than just reassuring:
- Exports contain credential references (an ID and a name), never the secrets. Importing onto a fresh instance means re-creating credentials with matching names. That is a feature, not a bug.
- Each node carries a
typeVersion. A workflow exported from 2.43 may use node versions that an older instance does not have. Export is forwards-compatible, not backwards. - Put the export in git before a major update. Rolling back a workflow is then a file import rather than archaeology.
If you want to go further, the public REST API can pull workflows on a schedule from a second n8n workflow, which is a pleasing kind of recursion and a real backup strategy.
Reading someone else's workflow
When you import a template from the n8n template library or copy JSON from a forum post, read it in this order before running it:
- Find the trigger. Is it a schedule (will run on its own once published) or a webhook (needs a caller)?
- Follow each wire and note which nodes write to anything: send messages, create records, delete files. Those are the nodes to point at a test destination first.
- Open every Code node and read it. A template's Code node is the one place where behaviour is not visible on the canvas.
- Check which nodes expect credentials. They will show a warning until you attach your own.
- Run it manually once, with the trigger's sample data, and read the execution before publishing.
That five-step read takes two minutes and would have prevented most of the "the template emailed my whole contact list" posts I have seen on the community forum. The tool is powerful precisely because a node with 500 items on its input does 500 things, which is wonderful until it isn't.
If you are still deciding whether n8n is the right tool at all, what n8n is covers that from the top. If you are past that and want to build, pick one of the four shapes above, start with a manual run, and publish only when the execution log looks the way you expected.
Frequently asked questions
An n8n workflow is a set of connected nodes that starts with a trigger and processes data step by step. Each node receives a list of items, does something with them (calls an API, transforms fields, makes a decision) and passes the result to the next node along a connection.
There is no hard limit on the number of nodes in an n8n workflow. Practical limits come from memory on the server running it and from how readable the canvas stays; past a few dozen nodes, splitting into sub-workflows called with Execute Workflow is usually the better design.
No. Manual runs from the editor do not count against an n8n Cloud execution limit. Only production executions count, meaning runs started by a trigger on a published workflow, and polling triggers only count when they find new data.
They are the same action under two names. Before n8n 2.0 the switch was labelled Active; 2.0 replaced it with Publish and Unpublish buttons, and separated saving from publishing so edits do not go live until you publish them.
Download each workflow as JSON from the editor menu, or run n8n export:workflow --all from the CLI to export every workflow on the instance in one go. Keep the files in git. Exports include credential references but never the secrets themselves.
Almost always because a node returned zero items, so nothing downstream had data to process. Open the execution, find the last node that shows output, and check its filter or query. An IF node whose condition never matches is the most common cause.
Related guides
Updating n8n takes about five minutes: back up your data folder, pull the new Docker image, and rest
Last verified: August 2026 n8n error handling works in three layers: Retry On Fail on the node, On E
Last verified: August 2026 The fastest way to learn n8n is to import a working workflow and take it
