All guides
Tooling8 min read
By Leeor MeirovitzLast updated:

n8n in production: patterns and pitfalls

An operations engineer reviewing an n8n workflow on a monitor in a working office

TL;DR

  • Treat n8n like real software: version control your workflows, add an error branch to everything, and make every workflow idempotent so a retry can't double-charge or double-send.
  • Self-host with the queue mode (Redis plus workers) the moment volume or reliability matters, and put your secrets in n8n credentials or a vault, never hardcoded in nodes.
  • n8n is the right call when you need self-hosting, complex logic, code nodes, or cost control at volume. Reach for Zapier or Make when you want zero ops and a handful of simple triggers.

Self-hosting vs n8n Cloud: pick the constraint you can live with

The first decision sets the tone for everything after it. n8n Cloud is the fastest way to get a workflow live: someone else patches the server, runs the database, and keeps the queue healthy. You trade money and control for time. For a team that wants automation without an ops practice, that trade is usually correct, and you should not feel clever for self-hosting when Cloud would have done the job.

Self-hosting earns its keep when you have one of three things: data that cannot leave your network, volume where Cloud pricing stops making sense, or workflows that need to reach private services (an internal database, a VPN-only API) that Cloud cannot see. The pattern we see most often is teams self-hosting on Cloud first to prototype, then moving to a container on their own infrastructure once a workflow becomes load-bearing. That is a healthy order of operations, not a failure to plan.

If you do self-host, run Postgres as the database from day one. The default SQLite is fine for a laptop and a quiet trap in production: it does not survive concurrent workers, and migrating off it later is a chore you will resent.

  • Choose Cloud when speed to value beats control and your data has no residency or network constraints.
  • Choose self-hosting for data residency, private-network access, or volume economics.
  • Always use Postgres in production, never the default SQLite, so you can add workers later.
  • Pin your n8n version explicitly and upgrade on purpose, not whenever the latest tag moves.
  • Budget for backups of the database and the encryption key from the very first deploy.

Error handling and retries: the error workflow is not optional

Here is the single highest-leverage thing you can do in n8n, and most teams skip it: build one error workflow and attach it to everything. n8n lets you designate a workflow that fires whenever another workflow throws. Without it, a failed run dies silently in the execution log, and you find out when a client asks why their invoice never arrived. With it, you get a message in Slack or email the moment something breaks, with the workflow name, the node, and the error attached.

Retries are the other half. Individual nodes have a retry-on-fail setting with a configurable number of attempts and a wait between them. Turn it on for anything that touches a network: HTTP requests, API nodes, database writes. A surprising share of production failures are transient (a rate limit, a five-second outage, a DNS hiccup) and a retry with backoff clears them without a human ever knowing. But retries are only safe if the work is idempotent, which is the next section and the reason people get burned.

  • Create one global error workflow and set it as the error workflow on every production workflow.
  • Send error alerts somewhere a human actually watches, with workflow name, node, and message.
  • Enable retry-on-fail on every network-touching node, with a sensible wait between attempts.
  • Distinguish transient errors (retry) from logic errors (alert and stop) so you do not retry forever.
  • Log the execution ID in your alerts so you can jump straight to the failed run.

Idempotency: design so a retry can't do damage twice

Idempotency means running the same operation twice produces the same result as running it once. It sounds academic until a retry fires a second Stripe charge or sends a duplicate onboarding email, and then it is the most concrete concept in your whole stack. Any workflow that can retry (which, if you followed the last section, is all of them) has to assume it might run twice on the same input.

The fix is usually a key and a check. Derive a deterministic key from the input (an order ID, an event ID, a hash of the payload) and check whether you have already processed it before doing the side effect. n8n does not give you this for free, so you build it: a lookup against a database table, a Redis SETNX, or an external API's own idempotency key header (Stripe and many others accept one). The discipline is cheap; the duplicate charge is not.

  • Derive a stable dedupe key from the payload: order ID, event ID, or a content hash.
  • Check a store (database row, Redis key) before performing any irreversible side effect.
  • Use the downstream API's idempotency-key header when it offers one, like Stripe does.
  • Make webhook handlers idempotent first; providers retry deliveries and will hit you twice.
  • Write the dedupe record in the same logical step as the side effect to avoid a gap.

Secrets and credentials: hardcoding is a leak waiting to happen

n8n has a credentials system, and the most common production mistake is not using it. People paste an API key straight into an HTTP node's header field because it works in the moment. The problem is that the value now lives in the workflow JSON, which means it lands in your version control, your exports, and anyone's screen-share. Credentials, by contrast, are stored encrypted and referenced by the node without exposing the value.

Everything in n8n credentials is encrypted with a single encryption key. Protect that key like a password, because it is one: lose it and your stored credentials become unreadable, leak it and the encryption is meaningless. Set it explicitly through the environment variable rather than letting n8n generate one it writes to disk, so the same key survives container rebuilds and you control where it lives. For larger teams, environment variables and an external secrets manager keep keys out of the n8n database entirely and let you rotate without editing workflows.

  • Never type a secret into a node field; create a credential and reference it instead.
  • Set the n8n encryption key explicitly via environment variable and back it up securely.
  • Keep credentials out of exported workflow JSON before committing anything to git.
  • Use environment variables or an external vault for keys you need to rotate regularly.
  • Give each integration its own credential so you can revoke one without breaking the rest.

Version control and environments: workflows are code, treat them like it

A workflow built in the editor and never exported is a single point of failure with a nice UI. The moment it matters, you want it in git: a JSON file you can diff, review, and roll back. n8n's source-control feature (on the higher tiers) syncs workflows to a git repository directly; on any tier you can export workflows through the CLI or API and commit the files yourself. Either way, the goal is the same: the editor is where you work, git is the truth.

Environments matter more than people expect. Editing a live production workflow is the n8n equivalent of editing code straight on the server, and it goes wrong the same way. The pattern we recommend is a separate development instance (or at least a clearly separated set of workflows) where you build and test, then promote a reviewed change to production. Tag your workflows, write a one-line description of what each does, and keep the naming consistent. Future you, debugging at the wrong hour, will be grateful.

  • Export every production workflow to git so you can diff, review, and revert.
  • Keep a development instance separate from production; never build live on prod.
  • Strip credentials and pinned test data from exports before committing.
  • Use consistent naming and a short description per workflow so the repo stays readable.
  • Promote changes through review rather than editing the running production version.

Monitoring, alerting, and scaling: queue mode is the grown-up setup

By default, n8n runs in a single process: the main instance handles the editor, the triggers, and the actual execution of every workflow. That is fine until it is not. Once you have concurrent executions, long-running jobs, or reliability expectations, you switch to queue mode: the main process accepts work and pushes it onto a Redis queue, and separate worker processes pull jobs and run them. You scale by adding workers, and a crashing job no longer takes the editor down with it.

Monitoring in n8n starts with the execution log, but the log is a place you look after something broke, not a system that tells you. Wire up real signals: the error workflow for failures, a heartbeat workflow that pings an uptime monitor on a schedule, and metrics from the n8n process and Redis into whatever you already run (Prometheus, Datadog, a Grafana board). The thing to watch is not just whether n8n is up; it is queue depth and execution duration. A queue that keeps growing means workers cannot keep up, and that is your signal to add capacity before the backlog turns into missed work.

  • Switch to queue mode (Redis plus workers) once volume or reliability matters.
  • Scale throughput by adding worker processes, not by making one process bigger.
  • Run a heartbeat workflow against an external uptime monitor so silence is an alert.
  • Watch queue depth and execution duration, not just whether the service responds.
  • Set execution data pruning so the database does not balloon and slow everything down.

When n8n is the right call vs Zapier or Make

n8n is not always the answer, and pretending it is does clients a disservice. The honest framing is about who absorbs the operational cost. Zapier and Make are managed services: you pay per task or per operation, you get a big library of polished integrations, and you never think about Redis or Postgres or upgrades. For a marketing team wiring a form to a CRM to a Slack message, that is the correct tool, and standing up a self-hosted n8n for it would be a vanity project.

n8n wins when the constraints push the other way: you need to self-host for data or compliance reasons, your logic is genuinely complex (branching, loops, code nodes running real JavaScript or Python), or your volume makes per-task pricing painful. Because you can run arbitrary code in a node, n8n handles the awkward middle that no-code tools choke on, and self-hosting means a high-volume workflow costs you compute, not a per-operation invoice that scales with success. The pattern we see is teams starting on Zapier, hitting a wall on either cost or capability, and moving the heavy workflows to n8n while leaving the simple ones where they are. That is a fine end state, not an inconsistency.

  • Choose Zapier or Make for simple, low-volume flows where zero ops is worth the price.
  • Choose n8n for self-hosting, data control, complex logic, or code-node requirements.
  • Watch per-task pricing: at volume, self-hosted n8n is often dramatically cheaper.
  • Mix them deliberately; keep simple flows managed and move heavy ones to n8n.
  • Factor in the real ops cost of self-hosting before you migrate to save money.

Want this built for your business?

We map the highest-leverage place to start and ship a first live system within two weeks.

Book a strategy call

Common questions

Is self-hosted n8n free?

The community edition is source-available and free to self-host, so you pay only for the infrastructure (a server, Postgres, and Redis if you run queue mode). Some features, like built-in git source control and certain enterprise controls, sit on paid tiers. For most teams the real cost of self-hosting is not a license, it is the operational time to run, monitor, and upgrade it.

How do I stop an n8n retry from sending duplicate emails or charges?

Make the workflow idempotent. Derive a stable key from the input (an order or event ID, or a hash of the payload), check whether you have already processed that key before doing the side effect, and use the downstream API's idempotency-key header when it offers one. With that in place, a retry that runs the same input twice produces one email and one charge, not two.

What database should I use for n8n in production?

Postgres. The default SQLite is fine for local testing but does not handle concurrent workers and will block you from moving to queue mode later. Start on Postgres from the first production deploy so scaling out is a configuration change, not a migration.

When should I switch n8n to queue mode?

When you have concurrent executions, long-running jobs, or reliability expectations that a single process cannot meet safely. Queue mode puts a Redis queue between the main instance and separate worker processes, so you scale by adding workers and a crashing job does not take the editor down. If you are still running everything in one process and seeing the queue or duration climb, it is time.

Should I use n8n or Zapier?

Use Zapier (or Make) for simple, low-volume automations where you want zero operational overhead and a polished integration library. Use n8n when you need to self-host for data or compliance reasons, your logic is complex enough to need code nodes, or your volume makes per-task pricing expensive. Many teams run both: managed tools for the simple flows, n8n for the heavy or sensitive ones.

The community edition is source-available and free to self-host, so you pay only for the infrastructure (a server, Postgres, and Redis if you run queue mode). Some features, like built-in git source control and certain enterprise controls, sit on paid tiers. For most teams the real cost of self-hosting is not a license, it is the operational time to run, monitor, and upgrade it.

Ask AI about X18 Global

“What does X18 Global (x18global.com) do for enterprise AI and automation - and can you summarise their guide "n8n in production: patterns and pitfalls"?”