Skip to content
All articles
Automation & AI

n8n in production: what separates throwaway workflows from maintainable ones

Andrey Gershengoren · · 9 min

The interesting question about an automation does not come up on the day it is built. It comes up six months later, when it needs to change. Either that is a twenty-minute adjustment, or it is the sentence "please do not touch it, it works" followed by a rebuild.

What decides between those two outcomes is not the complexity of the workflow, and not the tool either. It is a list of obligations that were met or were not.

The tool is not the problem

Up front, because this text reads wrongly otherwise: n8n is fit for production. A visual workflow is not inferior code, it is code in a different notation, with the same obligations.

The problem comes from the attitude the tool invites. "It is only an automation" leads to nobody asking the questions one asks about a service as a matter of course. A script that triggers payroll runs for five years is not a script any more, however it came about.

Demo and production do not differ in scale. They differ by the list below.

First: error handling as a design, not a hope

The first question for any workflow is what happens when a step does not work. The external service answers with a server error, the model runs into a timeout, the webhook arrives twice.

In a throwaway workflow the answer is: it stops and tells nobody. In a maintainable one there are retries with growing intervals, an error path for when retrying does not help, and somewhere to put what could not be processed at all.

The last point is skipped most often. Without such a place, failed items simply disappear, and afterwards nobody can say how many there were.

Second: idempotency

The question that most reliably reveals whether someone has production experience: what happens if this workflow runs twice on the same data?

This is not a theoretical case. Webhooks get delivered twice, retries fire after a timeout that actually succeeded, somebody re-runs an execution by hand. If the answer is "then the email goes out twice" or "then the record is in the CRM twice", the workflow is not production-ready, no matter how clean the graph looks.

The safeguard is rarely elaborate: a business key checked before writing, or a write that has no effect the second time. What is elaborate is retrofitting it once the duplicate records are already there.

Third: observability

A workflow that fails at night has to be able to say what happened. That means output at the places that will matter later, and a notification on failure.

The opposite is not "no logging". It looks more concrete than that: the failure is noticed a week later because somebody complains, and then reconstruction begins. Between those two states lies no question of technology, only the decision whether anyone is meant to notice.

Fourth: versioning and environments

Changes to a live workflow with no way back are the normal state of many installations. This is where tinkering and engineering separate most clearly, because what is missing here is not knowledge but discipline.

What belongs to it is well known and unspectacular: export into version control, a second environment to try things in, and changes run there before they go live. The effort is small and the return is invisible as long as nothing happens. Which is exactly why it gets left out.

I consider this the most honest test on the whole list. The other four can be forgotten while building. This one is left out deliberately.

Fifth: the boundary of responsibility

When a function node contains two hundred lines of JavaScript, the right answer is not to structure them better. It is that this logic does not belong there.

An orchestration tool connects services. It is not a place for application logic, because what application logic needs is missing there: tests, types, debugging with tools that step expression by expression. Logic of that size belongs in a service the workflow calls.

Knowing where the glue ends is the difference between someone operating a tool and someone deploying one.

The node that changes the rules

As soon as a language model sits in the graph, the previous assumptions no longer fully hold. Every other node is predictable in principle: same input, same output, and when it fails, it fails visibly.

A model node fails quietly. It delivers something that looks like a result, and the workflow keeps processing it, because nothing told it otherwise.

In practice one rule follows: a model's output is not a record until it has been checked. The check sits behind the node and answers at least two questions. Does the answer have the shape the next step expects, meaning structure, fields, types. And does its content make sense in domain terms, measured against what may legitimately come out at this point.

What happens next is a decision, not an accident: try again, hand it to the error path, or put it in front of a person. Without that check the error travels onward and becomes a number in a report that nobody questions any more.

The surcharge on build time

The price is build time, and it falls entirely at the start. A workflow with error paths, an idempotency check and control points takes considerably longer than the same workflow without. Both look identical at the end, as long as everything works.

There is friction in daily use too: going through a second environment means nothing gets changed in two minutes any more. That is the real reason this point is so often skipped, and it is understandable.

So whoever pays is paying for something they do not see at first. It becomes visible at the first change request. A throwaway workflow is cheaper to build and more expensive to own, because every change turns into a rebuild, and a rebuild costs building again.

Where throwaway is the right choice

Not every automation has to satisfy all of this, and claiming otherwise would be an ideology rather than a way of deciding.

A one-off data migration runs once and is deleted afterwards. A personal helper has exactly one user, who notices every fault immediately. An experiment for a week is meant to answer a question and then disappear. In all three cases the effort is not justified.

The difference is not in the result but in the intent. Maturity is not building everything solidly. It is deciding deliberately what you are building.

It becomes a problem only when the experiment turns into a production system without a decision. That rarely happens by resolution. It happens because nobody makes one.

Five questions, before the first connection

The five points are not a quality standard but a list of questions to answer before building: what happens on failure. What happens on a double run. Who learns about an outage. How do I get back. And where does this tool's responsibility end.

Whoever has answered them builds an automation that can be changed. Whoever never asked builds one that will have to be replaced, and does not know it yet.

n8nautomationidempotencyobservabilityLLM
Contact

First conversation: 30 minutes, free of charge, no presentation.

You describe the situation, I tell you whether and how I can help. No slides, no sales pitch.