A WordPress Plugin Conflict Debugging Checklist We Actually Use
The standard forum advice — deactivate every plugin, then turn them back on one by one — is the slowest…
Every self-hosted n8n instance we’ve inherited from a client started the same way: someone stood up a Docker container one weekend to stop copy-pasting leads into a spreadsheet. A year later that instance is syncing Shopify orders to a 3PL, generating invoices, and routing support tickets between Zendesk and Slack. Nobody decided to turn n8n into infrastructure — it happened one workflow at a time, and the operational discipline never caught up to the blast radius.
That’s the pattern we keep walking into, and it’s why this post exists. n8n is good software, and self-hosting it is the right call for a lot of our automation work — more on when it isn’t, further down. But “it’s just a workflow tool” is a dangerous way to think about something that’s now the only thing standing between a customer’s order and their inventory system. Here’s what we do differently once an instance crosses from internal convenience to “if this goes down, someone’s business stops.”
The first thing we configure on a new instance isn’t a workflow — it’s the thing that watches the workflows. n8n lets you assign an Error Workflow, instance-wide or per-workflow, triggered off a dedicated Error Trigger node whenever an execution fails. Most client instances we’ve inherited never had one set up, so a workflow could fail silently for weeks. Nobody notices until a customer emails asking where their order confirmation went.
Ours is intentionally plain: an Error Trigger node feeding a Slack node with the workflow name, execution ID, failed node, and a link straight back into that execution in the n8n editor.
Workflow failed: {{$json["workflow"]["name"]}}
Execution: {{$json["execution"]["id"]}}
Failed node: {{$json["execution"]["lastNodeExecuted"]}}
Error: {{$json["execution"]["error"]["message"]}}
Link: https://automate.client-domain.com/workflow/{{$json["workflow"]["id"]}}/executions/{{$json["execution"]["id"]}}
No dashboard, no triage bot. One Slack message per failure, in a channel a person actually reads, with enough context to fix it now or let it wait until morning. Twenty minutes to build, and it’s the difference between catching an API rate limit before the client notices and hearing about it from them.
Here’s where we part ways with a lot of n8n forum advice, which tends toward “just run queue mode, it’s more production-ready.” Queue mode is real: EXECUTIONS_MODE=queue, Redis as the Bull broker, separate workers pulling jobs off it. Past a certain volume it’s genuinely necessary. It’s also not free — now you’re monitoring Redis too, and you’ve traded one container to restart for three services that have to agree with each other.
For most client workloads we run — order sync, lead routing, report generation, a few hundred to a few thousand executions a day — a single well-specced instance in regular mode handles it fine, especially with n8n’s built-in N8N_CONCURRENCY_PRODUCTION_LIMIT capping concurrent executions without a queue at all. We move a client to queue mode only when the logs show real evidence: webhook responses queuing up, or execution start times drifting behind trigger times. Until then it’s complexity with no matching benefit, and complexity is exactly what this post argues against.
When we do reach for it — usually high-volume marketplace or multi-channel inventory sync — the shape looks roughly like this:
services:
n8n-main:
image: n8nio/n8n:1.68.1
environment:
- EXECUTIONS_MODE=queue
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- QUEUE_BULL_REDIS_HOST=redis
n8n-worker:
image: n8nio/n8n:1.68.1
command: worker --concurrency=10
environment:
- EXECUTIONS_MODE=queue
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_HEALTH_CHECK_ACTIVE=true
deploy:
replicas: 2
redis:
image: redis:7-alpine
Notice the pinned image tag, and the identical encryption key on both services — it has to match exactly or the worker can’t decrypt credentials the main process encrypted. A fuller setup adds a dedicated n8n webhook process behind the load balancer, so traffic never waits on the process serving the editor UI. Skip QUEUE_HEALTH_CHECK_ACTIVE and the worker exposes no health check — a bad thing to learn mid-incident.
Backing up n8n means backing up two things that have to survive independently: the Postgres database, and the N8N_ENCRYPTION_KEY that encrypts every stored credential. Lose the key and every API token and database password on that instance turns into ciphertext nobody can read, including you. We’ve watched this happen to a client who migrated servers without carrying the key over: workflows came back fine, and every credential had to be re-entered by hand.
So we back them up separately, in separate places. Postgres gets a nightly dump:
pg_dump -Fc n8n_prod | gzip > n8n-$(date +%F).sql.gz
rclone copy n8n-$(date +%F).sql.gz remote:client-backups/n8n/
The encryption key goes into the client’s own secrets manager the day the instance goes live, never into the same bucket as the database dump — otherwise anyone with read access to that bucket has both halves of the lock. We also run a weekly n8n export:workflow --all --output=./workflows/ into a git repository. That’s not disaster recovery, Postgres already covers that; it’s so a workflow change shows up as a diff, the way we’d review a pull request. Client asks why an order sync started skipping partial refunds? We point at the exact node that changed and when, instead of guessing.
A green health check tells you the process is running. It tells you nothing about whether the workflows inside it are doing their job, and nothing if the whole box is down. Two things we add on top of the error workflow above:
EXECUTIONS_DATA_PRUNE and a sane EXECUTIONS_DATA_MAX_AGE, the executions table grows without limit and Postgres performance degrades months later, right when nobody remembers this instance was ever configured. We set pruning during setup, not after someone notices the editor’s gotten slow.We don’t paste API keys into HTTP Request node headers as plain text, and we’ve turned down client requests to do it “just for now” more than once. Everything goes through n8n’s credentials system, encrypted at rest by that same N8N_ENCRYPTION_KEY. n8n also ships N8N_BLOCK_ENV_ACCESS_IN_NODE, which blocks expression and Code-node access to process environment variables entirely, and we turn it on across every client instance — an expression field that can read process.env is one compromised workflow away from leaking every secret on the box.
For clients handling payment data or PII, most of our e-commerce clients, we don’t run multi-tenant: each client gets its own instance and its own Postgres database, not a shared instance with folder-level permissions. More servers to patch, and we’ve made peace with that — a leaked credential in one client’s automation should never reach another client’s data. n8n’s External Secrets integration — Vault, AWS Secrets Manager, Azure Key Vault, Infisical — is worth turning on for larger clients on a license tier that includes it. For a five-person e-commerce brand paying us to automate their order flow, it isn’t: the credentials system plus per-client isolation gets most of the benefit for free.
We used to run Watchtower to auto-pull the latest n8n image on a schedule. We stopped after a minor version bump silently changed a node’s parameter schema and broke a production workflow overnight, with no warning and nothing to review. Now every image tag is pinned, upgrades get tested against a staging container running a copy of the production database first, and the version bump happens on our schedule, not Docker Hub’s.
None of this is exotic. It’s the same discipline you’d apply to any other piece of production infrastructure — worth writing down only because n8n’s editor makes it so easy to build a workflow that it’s easy to forget you’ve built a dependency. Our advice cuts against our own self-hosting bias: if the automation footprint is small, a handful of internal workflows with no customer-facing failure mode, n8n Cloud is the right call, and we’ll say so even when it costs us a shorter engagement. Self-hosting earns its keep once there’s a compliance reason to control the infrastructure, a cost reason at real volume, or data that shouldn’t leave a client’s own cloud account. Below that line, the overhead above isn’t worth either side’s time.
Tell us what you're building and we'll tell you honestly whether we're a fit.
The standard forum advice — deactivate every plugin, then turn them back on one by one — is the slowest…
Almost every brief grows the word "AI" somewhere in it, and hardly any of them say what that means. These…
Checkout.liquid died in two waves — August 2024 for the core checkout, August 2025 for Thank You and Order Status…