I get asked about these two constantly, usually as if they're competitors. They're not. One of them is where the thinking happens. The other is where the plumbing lives — the parts that connect systems that were never built to talk to each other. Almost everything I've built runs on some split of the two.

2 tools splitting the work: one runs the reasoning, one runs the plumbing
12 serverless agent endpoints live on Vercel right now, across two fully separate accounts
6 outside systems one single n8n workflow touches to build one weekly report: Toggl, Monday, Claude, Docs, Drive, Gmail
3 real bugs in that same workflow that stayed invisible until it was actually tested live, not just built

Vercel: where the reasoning happens

Vercel hosts serverless functions — small pieces of code that spin up on demand, run, and disappear. That's where I put every AI agent that needs to actually reason over live data: read a real order, decide what it means, call a second tool, form an answer. Each agent is its own function with the Claude API's tool-use loop wired in directly — Claude gets a real set of tools, decides which to call, reads what comes back, and decides again, sometimes several times before it ever answers.

Right now that's 12 agents split across two completely separate Vercel accounts with separate billing — six running my day job's client-facing AI team, six running my own Etsy shop. Same underlying pattern both places, zero shared infrastructure between them on purpose.

The other thing Vercel gives me is Cron Jobs — real scheduled triggers, not a workaround. Three of my agents now run unattended on a schedule and email me the result without being asked: one every morning, one every week, one every day that's specifically built to stay quiet unless something's actually wrong. That last one only speaks up if its own answer starts with a literal flag word my code checks for — a daily update that fires whether or not anything happened gets ignored by week two.

n8n: the plumbing for things that shouldn't live in code

n8n is a visual workflow builder — nodes connected by lines, each one a step: a webhook, an API call, a scheduled trigger, a branch. I use it for exactly the things that don't need Claude reasoning over them at all — moving data between systems, on a schedule or in response to an event, reliably, without me writing and redeploying a script every time the shape of the trigger changes.

The clearest real example: a weekly report workflow that pulls hours from Toggl, project data from Monday, generates a written summary through Claude, writes that summary into a real Google Doc, and drops a Gmail draft — six outside systems, one workflow, no code deploy required if a step in the middle needs to change.

It also runs the Slack side of my day job's AI project manager — a webhook receives the Slack event, and the workflow forwards it to the right Vercel-hosted agent, which does the actual reasoning and hands back an answer for n8n to post. n8n doesn't try to be smart here. It's a very reliable relay.

Building that six-system report workflow surfaced three real bugs that a demo never would have. Each one only showed up because the workflow ran against real data, repeatedly, not because a prompt was wrong.

  • The AI step returned nothing, silently. Claude was spending its entire token budget on internal reasoning before it ever got to the actual answer. The fix was explicitly turning that reasoning mode off for this call — leaving it on the default setting wasn't the same as disabling it.
  • Asking the model to "return valid JSON" broke on real content. With six clients' worth of text in one response, it embedded an unescaped line break inside a string and the parser choked, even though the content itself was fine. The fix wasn't a better prompt — it was switching to Claude's tool-use feature, which enforces valid, correctly escaped structured output at the API level instead of hoping a prose instruction gets followed exactly.
  • A "successful" step had actually failed. One integration's API returns a normal 200 response even when it silently rejects what you sent it — the real failure is buried in a field inside the body, not the status code. Without explicitly checking that field, a rejected step looks identical to a working one in the execution log.

None of these are exotic. They're the ordinary cost of connecting real systems to each other, and every one of them was invisible until the workflow actually ran against live data more than once.

Where the split actually lands

If a step needs judgment — read this, decide what it means, call another tool if needed — it goes on Vercel as a real agent. If a step needs to move data reliably from one system to another, on a trigger, without reasoning about it, it goes in n8n. Trying to do the plumbing in a Claude prompt makes it flaky. Trying to do the reasoning in a no-code workflow node makes it shallow. Once I stopped trying to make one tool do both jobs, both got a lot more boring to maintain — which, for infrastructure, is exactly what you want.

n8n workflow names referenced here are internal — this describes the pattern, not a walkthrough of my actual account.