Coopen / Automation / n8n workflows
n8n workflows: how they actually work.
An n8n workflow is a chain of nodes that passes data from one step to the next: something triggers it, each node transforms or sends the data it receives, and the result lands wherever you told it to go. That much is easy. What trips people up is the data model underneath — so this page explains that properly, with examples you can copy, before it explains what we do.
Platforms we build on
On this page
What an n8n workflow is
n8n is a workflow automation tool you can run on your own server. You build automations visually on a canvas: each box is a node, the lines between them are the path the data takes, and the whole thing is triggered by a schedule, a webhook, an event in another app, or a button you press.
Where it differs from the hosted connectors most people meet first is ownership. You can self-host it, which means execution volume stops being a billing event and your data never leaves infrastructure you control. It is fair-code licensed rather than fully open source: the source is available and self-hosting for your own business is free, with restrictions on reselling it as a service.
The other difference is depth. A workflow can branch, loop, call sub-workflows and drop into JavaScript or Python whenever the visual nodes run out of expressive power. That makes it viable for real business logic rather than only for glue between two SaaS apps — and it is why we default to it when a client needs serious automation without a licence per task.
Anatomy
The six parts of every workflow
Learn these and the rest of the tool is detail.
- Trigger node — What starts the run: a schedule, an incoming webhook, an app event, or manual execution while you build.
- Regular nodes — Everything after the trigger — call an API, query a database, transform data, send a message.
- Connections — The lines between nodes. They define order and branching; a node only runs when data reaches it.
- Items — The data itself. Every node receives an array of items and outputs an array of items. This is the concept everything else depends on.
- Expressions — Small snippets like {{ $json.email }} that pull values out of the data flowing through, evaluated per item.
- Credentials — Stored separately from the workflow and encrypted, so an API key is configured once and reused everywhere.
The core concept
How data moves between nodes
This is the part worth reading twice, because almost every confusing n8n behaviour traces back to it. Data travels as an array of items. Each item is an object with a `json` property holding your actual data, and optionally a `binary` property for files.
Most nodes run once per item automatically. If a node outputs fifty items, the next node executes fifty times — you do not write a loop for that, it is the default behaviour. That is why fetching fifty rows and then calling an API "once" quietly makes fifty API calls.
The corollary catches everyone at least once: if a node outputs zero items, every node after it simply does not run. Nothing errors, nothing is logged as a failure, the execution just ends early and looks successful. When a workflow "does nothing" with no error, an empty item array is almost always why.
{{ $json.email }}
// A field on the item currently being processed.
{{ $('Fetch Orders').item.json.total }}
// The matching item from an earlier node, by node name.
{{ $now.minus({ days: 7 }).toISO() }}
// Dates use Luxon. Handy for "everything since last week" filters.
{{ $json.lines.map(l => l.sku).join(', ') }}
// Plain JavaScript works inside expressions.When a branch needs data from two different paths, the Merge node joins them — by position, by a matching field, or by simply appending one set to the other. Reaching for the Merge node is usually the fix when a workflow "loses" fields halfway through: the data did not disappear, it went down a different branch.
Examples
Three workflows worth copying
These are shapes we build repeatedly for clients. None of them needs a Code node, and all three are a few hours of work once the credentials exist.
- Inbound lead to CRM to Slack — Webhook trigger → validate the payload → look up whether the company already exists → create or update the CRM record → post to the sales channel with the enrichment attached.
- Nightly report from two systems — Schedule trigger → query the database → fetch yesterday's figures from an API → Merge by date → format → email the summary and write the row to a sheet.
- Document inbox to structured data — Email trigger with attachment → extract the file → send it to an AI extraction step → validate the fields against rules → post to your accounting system, or route to a human if confidence is low.
- Sub-workflow for the shared part — The "notify a human and wait" logic lives once in its own workflow and is called by the other three via Execute Workflow. Change it once, every caller gets it.
When nodes are not enough
The Code node, and when to reach for it
The Code node runs JavaScript (or Python) over the items passing through. It has two modes and picking the wrong one is a common source of confusion: "Run Once for All Items" gives you the whole array to work with, while "Run Once for Each Item" gives you a single item and runs repeatedly.
Use it for reshaping data, non-trivial filtering and calculations that would take six visual nodes to express. Do not use it as a place to call APIs and hide half the workflow — the value of a visual workflow is that someone else can read it, and a hundred-line Code node throws that away.
// Keep only the big orders, and reshape them for the next node.
const items = $input.all();
return items
.filter((item) => item.json.total > 100)
.map((item) => ({
json: {
id: item.json.id,
customer: item.json.customer.name,
total: item.json.total,
},
}));Every Code node must return an array of items shaped like { json: {...} } — returning a bare object is the most common error here.
Production
Error handling: the part that decides if it survives
A workflow that works on the happy path is a demo. What makes it a system is what happens when an API rate-limits you, a token expires, a field arrives null, or a third party has a bad afternoon. n8n gives you four mechanisms and a production workflow generally uses all four.
- Retry on fail — Per node: number of attempts and the wait between them. Fixes the majority of transient API failures on its own.
- Continue on fail — Lets the workflow carry on past a node that errored, so one bad record does not kill a batch of five hundred.
- Error workflow — A workflow-level setting pointing at a second workflow that runs when this one fails — where you put the alerting.
- Error Trigger node — The entry point of that error workflow. It receives what failed, in which node, with which data.
The other half is idempotency. If a workflow can run twice on the same input — and eventually it will, through a retry or a duplicate webhook — it must not create the invoice twice. Keying on an external ID and checking before creating is boring and it is what separates automation people trust from automation people quietly turn off.
Running it
Self-hosted or n8n Cloud
Both are legitimate. The decision is usually about data and volume rather than about features, since the editor and the nodes are the same either way.
| Self-hosted | n8n Cloud | |
|---|---|---|
| Where data lives | Your infrastructure | The vendor's |
| Cost shape | Flat — your server, any volume | Per workflow execution |
| Who patches it | You (or us) | The vendor |
| Scaling | Queue mode with Redis and worker processes | Handled for you |
| Best when | Sensitive data, high volume, internal systems | Small volume, no ops appetite |
If you self-host, three settings matter more than the rest: set a persistent encryption key before creating any credentials — regenerate it later and every stored credential becomes unreadable; turn on execution data pruning, because execution history grows without limit and will eventually fill the disk; and put it behind a proper reverse proxy with the webhook URL configured, or your webhook nodes will hand out addresses nobody can reach.
Comparison
n8n vs Zapier vs Make
They overlap more than their marketing suggests. The honest split is that hosted connectors are faster to start and priced per unit of work, while n8n costs more setup and then stops charging you for volume.
| n8n | Zapier | Make | |
|---|---|---|---|
| Hosting | Self-host or cloud | Vendor cloud only | Vendor cloud only |
| Billing unit | Workflow execution (flat if self-hosted) | Per task | Per operation |
| Complex logic | Branching, loops, sub-workflows | Limited | Good visual routing |
| Custom code | JavaScript and Python nodes | Code steps | Limited |
| Data residency | Yours, if self-hosted | Vendor | Vendor |
| Licence | Fair-code, source available | Proprietary | Proprietary |
Our rule of thumb: three simple connections between popular SaaS apps and nobody to run a server, use a hosted connector. Steady volume, sensitive data or logic with real branching, use n8n. A legacy system with no API at all is neither — that is an RPA problem.
From experience
The mistakes we see most
Every one of these has cost somebody a weekend, including us.
- Building in production — Test executions hitting live systems. Use test credentials and a staging path, or you will email real customers.
- Ignoring the item model — A node that "runs once" actually running per item, quietly making hundreds of API calls.
- No error workflow — Failures nobody notices for a week, because the workflow is silent when it dies.
- Everything in one workflow — A canvas with eighty nodes that nobody dares change. Split it and call sub-workflows.
- No version control — Workflows only exist inside the instance. Export the JSON into a repository so changes are reviewable and revertible.
- Losing the encryption key — Rebuild the container without persisting it and every credential has to be entered again.
How it works
What we do when a client hands us this
You do not have to become an n8n team to get the benefit of one.
Map the process first
On paper, including the exceptions. Half the time the process gets simplified before anything is built.
Build with the failure path
Retries, error workflow and idempotency from the start, not bolted on after the first incident.
Host it properly
Your infrastructure or ours: encryption key persisted, pruning on, backups, and monitoring that alerts a person.
Hand it over documented
Named nodes, exported JSON in your repo and a walkthrough — so small changes never require calling us.
Results
What you get out of it
Cost at any volume
Self-hosted execution means growth is not a per-task billing event.
Data and workflows
Running on your infrastructure, exported to your repository, documented.
Not set-and-forget
Alerting on failures, so a broken workflow is noticed by us and not by a customer.
FAQ
n8n workflow FAQ
What is an n8n workflow?
It is an automation built from connected nodes. A trigger node starts it — a schedule, a webhook or an app event — and each following node receives data, does something with it and passes the result on. Data travels as an array of items, and most nodes run once per item.
Is n8n free?
Self-hosting is free for your own business use. It is fair-code licensed under the Sustainable Use License rather than a standard open-source licence: the source is available, but there are restrictions on offering it to third parties as a service. The vendor also sells a hosted cloud plan and an enterprise edition.
Why did my workflow stop halfway with no error?
Almost certainly a node returned zero items. Downstream nodes only run when data reaches them, so an empty result ends the execution early and it still looks successful. Check the output of each node in the execution log to find where the items ran out.
How do I reference data from an earlier node?
Use an expression like {{ $('Node Name').item.json.field }}. For the item currently being processed, {{ $json.field }} is enough. If the branches have diverged, use a Merge node to bring the data back together rather than reaching across.
Do I need to know JavaScript?
Not for most workflows — the visual nodes and simple expressions cover a lot. JavaScript helps when you need to reshape data or express logic that would otherwise take many nodes, and that is where the Code node comes in.
How does n8n compare to Zapier?
Zapier is faster to start and bills per task on the vendor cloud. n8n takes more setup, can be self-hosted so volume stops costing per unit, keeps data on your own infrastructure, and handles branching, loops and custom code far better. Small and simple favours Zapier; volume, sensitive data or real logic favours n8n.
Can n8n do AI steps?
Yes — there are nodes for language models and agents, which is useful for classifying incoming messages, extracting fields from documents and drafting replies. We build these with a validation step after the model, so its output is checked before it triggers anything that matters.
Can you build and run this for us?
Yes. We design the workflows, host the instance, wire up monitoring and hand everything over documented — including the exported JSON, so you can take it fully in-house whenever you want.
Is Coopen affiliated with n8n?
No. We are an independent software studio that builds on it because it fits a category of problem well. n8n is a trademark of its respective owner. We recommend it when it is the right tool and something else when it is not.
More automation
Related services
Ready to cut this cost?
Tell us the repetitive work slowing your team down. We'll show you what it costs — and what to automate first.