When I reach for n8n and when I write custom code
A decision rule from a year of building both for client systems, and why communication decides more cases than code.
I’m an official n8n creator, and a decent share of the systems I ship contain no n8n at all. After a year of building client automations both ways, the choice has settled into a rule I can say in one line: n8n owns the orchestration, code owns the computation. And underneath it sits a second rule that decides more cases than the first: the client has to understand what they bought.
What decides it
Three questions settle nearly every case.
Who has to understand this in six months? This is why I started with n8n in the first place. The canvas works like the minimap in LoL: one glance and you know the state of the whole game. An owner can look at their workflow and watch leads enter, branch, and land somewhere, and that picture does more for the relationship than any status report I could write. The wins n8n gives me are communication wins. When a client can see what the automation does and how it benefits them, they trust it, they use it, and they renew it. Hand that same owner a folder of Python and I’ve earned a maintenance contract while they’ve earned a dependency. Some clients want exactly that arrangement. Plenty would rather own their system.
How branchy is the logic? Workflows shine at linear pipelines with a few branches: trigger, transform, route, deliver. Somewhere past a couple dozen nodes, a canvas stops being documentation and turns into a murder board with string, and the communication advantage that justified n8n dies with it. When I catch myself nesting IF nodes three deep, that’s my signal to move the logic into a script.
Does it need tests? Anything touching money, deduplication, or irreversible writes gets code, because code gets unit tests, version control, and reviewable diffs. My CRM import scripts are idempotent and I can prove it, because tests run the same import twice and assert nothing duplicated. You can export a workflow and diff it as JSON, but reviewing a 400-line JSON diff of node positions is nobody’s idea of quality control.
The hybrid that actually ships
On real projects the either-or framing dissolves, because the winning pattern uses both layers for what they’re good at. n8n handles the schedule, the webhook, the retries, the error notifications, and the visibility. The gnarly middle step, the scoring logic or the transformation with fourteen edge cases, lives in a script the workflow calls. The client sees a readable five-node canvas. The complexity lives where it can be tested. When either layer needs surgery, the other keeps standing.
Maintenance is the real bill
Build cost differences between the two approaches are noise. The bill that matters shows up over the following year, and it taught me both halves of the rule. Visual workflows fail loudly and legibly: a red node, a timestamped execution log, an obvious retry button, so a lot of failures resolve without me. Code fails quietly unless observability was built in, and observability is exactly the part that gets skipped when a script was “just a quick fix.”
The flip side is churn. Platforms update nodes and deprecate behaviors, and a dense workflow touching a bunch of third-party services accumulates small breakages. Boring stdlib code keeps running unchanged for years. So volatile integrations lean workflow, stable logic leans code, and the orchestration line between them is the most durable architecture I’ve found. A year in, that line has held on every project. We’ll see what year two does to it.