From n8n to code: when an AI workflow becomes a product
n8n is great for prototyping AI automation. These are the signs a workflow should move to code: tests, versioning, permissions and cost control.
From 2024 to January 2026, at PowerX, I built workflows with LangChain, Ollama and n8n wired to internal data and APIs. Today I build apps and AI agents directly in code, using Claude Code and Codex. This isn't a list of n8n's flaws. It's an engineering comparison: what visual AI automation tools are good at, and the point where a workflow should become code.
What n8n does well
Visual workflow tools solve a lot of real problems. Their strengths are clear:
- Fast prototyping. You can wire a webhook to an API and a spreadsheet in minutes and watch the data move through each step.
- Simple integrations. Copying a record from one system to another, sending an alert when something changes, scheduling a job. For that, a ready-made node beats an SDK.
- Visibility for non-developers. The diagram doubles as documentation. Someone in operations can follow what happens without reading code.
- Trying out an AI agent idea. Chaining a model, a search and a reply to see whether the idea holds up is exactly where the canvas shines.
If a workflow has a few steps, one owner, and errors you can fix by hand, I don't see a reason to switch. Code costs more up front.
Search data shows a shift
On Google Trends, comparing the first and last quarters of a 12-month window, searches for "n8n" fell about 58% in Brazil and by half worldwide. Over the same period, "Claude Code" grew almost 5x in Brazil and doubled worldwide. That doesn't prove one tool is better than the other. It does show a lot of people looking for an n8n alternative, or at least looking around: writing the agent in code got cheaper once a coding assistant does much of the typing.
Signs a workflow has become a product
n8n isn't the problem. The problem starts when a workflow stops being internal automation and becomes a product: it has users, other people's data, money, and rules that can't break. These are the signs I look for.
1. You need tests
In a visual workflow, testing usually means running it again and eyeballing the output. That works until about the tenth rule. After that, any change can break an old case without anyone noticing.
In LedgerJob, a SaaS for US construction contractors, the backend has 59 test files (Vitest) with 347 declared test cases. A real bug shows why that matters: the assistant could book an appointment "from 6 pm to 5 pm." The fix moved the rule into the service layer, with a test that keeps it from coming back.
2. You need versioning and review
An exported workflow is a large JSON file that includes the position of every node on the screen. You can keep it in Git, but the diff mixes logic changes with layout changes. Reviewing that in a pull request is painful.
In code, a change looks like a change. A new agent tool is a file with a type, a description and a schema. The reviewer reads the rule, not the coordinates of a box.
3. Permissions and multi-tenancy
When several companies share one system, every read has to know whose data it is. That's easy to forget in a node and hard to audit later.
In Reachant, a B2B lead-list builder, every read goes through a scoped(Model) function that raises if no account is set. A route missing that guard fails loudly instead of returning another account's data. In LedgerJob, identity comes from the API key, never from the model: the key carries the tenant, user and role, and the MCP server acts as that user, with the same limits.
4. Many tools for one agent
An AI agent with three tools fits nicely on a canvas. With dozens, the diagram turns into a map nobody reads, and the same action ends up duplicated across two workflows.
LedgerJob has a single list of 66 tools. It backs both the in-app chat and the MCP server. A new tool shows up in both places in the same deploy, with no duplicated code. A generic example of the shape:
// generic example, not project code
export const sendQuoteEmail: AgentTool = {
name: "send_quote_email",
description: "IRREVERSIBLE. Emails the quote to the client.",
requiresConfirmation: true,
input: z.object({ quoteId: z.string().uuid() }),
run: (ctx, { quoteId }) => quotes.sendEmail(ctx, quoteId),
};
A typed schema, a confirmation flag, and the rule delegated to the service. All of it is testable and shows up in the diff.
5. Actions you can't undo
Sending email, sending SMS, spending money with third parties, deleting data. In an automated workflow, those actions run as soon as the node is reached. In a product with an AI agent, you want a brake.
In LedgerJob, 16 of the 66 tools require human confirmation. An irreversible action never runs inside the agent loop: it becomes a card the user confirms with a click. The outcome goes back into the history, so the model can't claim it did something that didn't happen.
6. Business rules outside the route
This only shows up once a system has more than one entry point. In LedgerJob, business rules live in the service layer, not in routes, because the agent and the MCP server skip the HTTP validators. In a visual workflow, validation tends to sit in the entry node. Add a second entry point and the rule has to be copied.
7. Observability and cost control
An agent calls a model, and the model charges per token. Data vendors charge per call. Without explicit limits, a large response or a runaway loop turns into a bill.
In LedgerJob, the agent loop is capped at 8 iterations per turn, and each tool's output is truncated at 6,000 characters so a large listing can't blow up the context. In Reachant, credits are debited with a conditional UPDATE, so two workers can't spend the same balance. With no balance left, the paid step is skipped and the lead keeps its basic data. Each debit logs the vendor cost to a ledger. Rules like these take a few lines of code, with a test.
An n8n alternative isn't another visual tool
Once a workflow crosses these lines, swapping one canvas for another doesn't help much. What helps is the ordinary practice of software engineering: tests, types, code review, versioned deploys.
Reachant is an example of that move. It replaced an old Google Maps scraper with a product that runs searches off the request in a thread pool, scrapes through a fetcher that blocks private IPs and re-checks every redirect, handles Stripe webhooks idempotently, and has 558 pytest test functions across 82 files, plus 17 in the MCP package. None of those pieces is exotic. Together, they're what separates a script that runs from a system someone else can use.
How I decide today
A simple rule:
- Keep it in a visual workflow: few steps, one owner, no third-party customer data, cheap mistakes.
- Move it to code: if any of these show up: it needs tests, more than one person edits it, there's more than one customer in the same system, the agent has many tools, some action is irreversible, or the cost per run matters.
Writing code also got faster. I build with Claude Code: LedgerJob, for example, was built that way, and I designed the backend, the agent and the MCP server. The assistant speeds up the typing. The architecture decisions, the limits and the tests are still the engineering work.
If you have an AI automation workflow that has started asking for these things, get in touch.
All articles