We started running n8n for clients in 2023. Self-hosted, mostly small teams, mostly back-office stuff: CRM sync, invoice flows, lead routing, “when X happens in Stripe, do Y in Slack.” Two years and roughly a dozen client deployments later, here's the honest report.
Where n8n shines.
For a certain shape of workflow, n8n is the best tool we have. Specifically: short, branching, integration-heavy workflows that don't need to scale beyond a few requests per minute, but need to talk to five different SaaS APIs and survive when one of them is down.
The killer feature is visibility. When a workflow fails, you can see exactly which node, see the input, see the output, retry from the failing step. That's a debug experience proper code workflows still don't match.
Where it's a workaround.
Three places we keep hitting friction:
Loops. SplitInBatches is the official answer and it's awkward enough that we've rewritten three flows in plain TypeScript because the loop logic became unreadable. If your workflow has nested iteration, n8n is fighting you.
Long-running steps. Anything that takes more than ~60 seconds (a big API import, a video transcode kickoff) we now hand off to a proper queue (BullMQ on the same Postgres) and let n8n just trigger and poll. Self-hosted n8n can lose state if the worker restarts mid-execution.
Secrets. n8n stores credentials in an encrypted local store, which is fine until you want secrets-as-code. We've standardised on injecting via environment variables and using n8n credentials as references, but it's not as clean as a proper secrets manager.
What we've replaced.
Two categories of workflow have moved out of n8n entirely:
LLM-driven flows. Two years ago we built a couple of “classify this incoming email, route it accordingly” agents in n8n. They worked. Then they started to need eval sets, version control on prompts, and observability across tool calls. None of that lives well in a flow editor. They're all in LangGraph now, in code, with proper CI.
Anything customer-facing. We tried, once, to wire an n8n form node as a public intake form for a client. It worked, but the styling escape hatches were ugly and the form felt like it came from a different decade than the rest of the site. Now we always build the form ourselves and webhook into n8n only for the back-office plumbing.
n8n is great as a glue layer. Stop using it when the workflow is the product.
Would we choose it again?
For the back-office glue jobs we use it for? Yes, every time. The alternatives we've evaluated, Zapier, Make, custom code, each trade something we care about (self-hosting, cost-at-scale, debuggability).
Would we use it for AI workflows? No, not in 2025. Use LangGraph or LangChain or write your own orchestration; n8n's LLM nodes are fine for demos and brittle in production.
Would we use it for the entire stack? Also no. n8n in our setups is one tool among several. It does the boring glue beautifully, and we let other tools (real databases, real queues, real code) do what they're good at.
That's a more useful answer than “n8n is great” or “n8n is bad.” The honest answer is n8n is great at one shape of work and bad at most others. Know which shape your work is.
— A.B., from the studio, after a workflow review.