Most automation-stack regret I see follows one of two scripts. A team picks a visual builder because the demo was fast, then the first production invoice lands and the per-operation math turns a cheap workflow into a real budget line. Or an engineer builds a beautiful custom Python service, changes jobs eight months later, and the company is left holding a black box nobody dares redeploy. Both failures were avoidable, and neither had anything to do with which tool is "best." The tool was scored on the wrong questions — usually familiarity and demo speed — instead of the four that actually predict regret.
This is the stack-selection portion of the audit methodology I run before building anything. It scores the workflow, not the tool. Same rubric every time, four questions, and the verdict usually writes itself.
Question 1: What does the math say at production volume?
Not demo volume. Production volume, at the busiest month you can plausibly hit.
The three options price fundamentally differently, and this is where most surprises live. Make bills per operation — and every module execution inside a scenario counts. A 12-module scenario processing 10,000 records is not 10,000 operations; it is on the order of 120,000. n8n bills per workflow execution (or, self-hosted, costs you a small server plus the discipline to patch it), so the same job counts as 10,000 executions — or one, if you batch. Custom Python has almost no per-run cost at this scale; its price is nearly all engineering time, paid up front and again at every change.
None of these models is wrong. But you have to run your own numbers through all three before committing, because the curves cross. Low volume, simple flow: the visual builders are effectively free and Python is the expensive option once you price the hours. High volume, many steps: per-operation pricing becomes a tax on scale that compounds with every module you add.
Question 2: How much judgment lives in the flow?
Visual builders are excellent pipe-fitting: trigger, transform, route, deliver. They get painful when the logic branches hard — nested conditionals, lookups that feed other lookups, retry logic that depends on why something failed. My working heuristic: when the canvas needs a scrollbar in both directions, or a router feeds another router, the workflow is telling you it wants to be code.
The inverse holds too. If the flow is genuinely linear — form submission in, enriched row out — writing custom Python for it buys you nothing but a maintenance obligation.
Question 3: What does failure cost, and will you see it?
Every stack fails. The question is whether failure is loud or silent, and what a silent one costs you. A dropped Slack notification is trivia; a dropped invoice or a double-fired CRM update is not. Before choosing a tool, I decide what the workflow's failure posture has to be, then check the tool can express it. In n8n that's an error workflow wired to every production flow. In Make it's explicit error-handler routes on the modules that matter. In Python, it's a pattern like this — retries with backoff, then a dead-letter record instead of a silent drop:
def with_dead_letter(max_tries=3):
def deco(fn):
def run(record):
for attempt in range(max_tries):
try:
return fn(record)
except TransientError:
time.sleep(2 ** attempt)
dead_letters.write(record) # never silently drop
alert(f"{fn.__name__} exhausted retries", record.id)
return run
return deco
The rule I hold every build to, no-code or code: no silent drops. If a record can't be processed, a human finds out from the system — not from an angry customer three weeks later. If you can't express that rule in the tool you're evaluating, the evaluation is over.
Question 4: Who owns this in month six?
This is the question teams skip because the honest answer is uncomfortable. If nobody on staff is comfortable with a terminal, self-hosted n8n and custom Python are liabilities no matter how elegant the build — you are one departed contractor away from an outage you can't diagnose. If you do have engineers, an un-versioned visual workflow is the liability: no diff, no code review, no rollback, and the only change history is memory.
Mitigations exist for both. n8n workflows export to JSON and belong in git — that's twenty minutes of setup and it converts "what changed?" from an argument into a diff. And if the verdict is custom code, the runbook, README, and recorded handoff are part of the build, priced into the quote, not a nice-to-have. A script without a runbook isn't an asset; it's deferred consulting revenue for whoever gets called when it breaks.
The verdicts the rubric produces
- Make — linear flows, modest volume, owned by non-engineers, speed-to-live matters most.
- n8n — mid-complexity flows, cost-sensitive volume, someone on staff comfortable self-hosting (or the managed tier priced against your execution count).
- Custom Python — heavy branching, real judgment in the flow, high volume, an engineer who owns it and a handoff document that outlives them.
- The hybrid that quietly wins most often — a visual builder as the trigger-and-glue layer, a small Python service for the judgment-heavy core, one webhook between them. Each layer does what it's cheap at.
The pattern behind all four questions is the same: the subscription fee is almost never the real cost. The real costs are engineering time, per-operation math at a volume you didn't model, and the 2 a.m. failure nobody saw. Score those before the demo impresses you, and the choice stops being a matter of taste — and stops being a regret.