Dear n8n Support Team,
We are reaching out for help with a “ghost execution” issue in our self-hosted n8n infrastructure. We initially used a simple three-container setup (main n8n, PostgreSQL, runner). However, as our workload increased, we decided to scale up to the following architecture:
Host information:
Ubuntu 24.04.4 LTS + Docker
Intel(R) Xeon(R) CPU E5-2690 v4
16 GB RAM
After migration, we encountered a serious problem: multiple parallel executions of the same workflow with identical execution IDs, leading to race conditions. This causes errors when working with files (e.g., trying to delete a file on FTP that has already been deleted by the “ghost”), databases, and other components. This issue matches exactly the one described in this community post:
http://community.n8n.io/t/ghost-sub-executions-duplicated-runs-while-parent-execution-shows-single-calls/190813
We tried various solutions found online, but none helped. Moreover, even when we reduced the setup to a single worker+runner pair, the problem persisted.
We suspect that while trying to configure a scalable environment and then fix the ghosting issue, we likely made multiple configuration mistakes. Therefore, we would greatly appreciate it if you could provide an example of a correct, production‑ready configuration for two worker+runner pairs, Redis, main n8n, and a database – one that is free from ghost executions.
Thank you very much for your assistance. We look forward to your recommendations.
welcome to the n8n community @Alex.86
From what you described, I’d focus first on the queue-mode configuration consistency rather than scaling size. Duplicate executions with the same execution ID usually suggest multiple processes are competing for the same jobs or an old process is still consuming the queue. I’d verify that all containers use the same Redis/database settings, only the intended services run worker mode, and no leftover containers from the previous setup are still connected. I’d also check worker concurrency settings, container restart loops, and whether all instances are running the exact same n8n version. Before scaling to two workers again, I’d test with one clean worker + Redis + main instance from scratch and confirm the issue disappears, then scale gradually.
Thanks for the quick reply! Right now we have a simplified configuration: the main container, 1 worker and redis - the problem persists.
@Alex.86
Thanks for the update.
In this case, I’d stop looking at scaling and start looking at stale queue state or duplicated trigger sources. I’d check whether old jobs are still sitting in Redis, whether the same workflow can be triggered from more than one source, and whether any old containers/processes are still registered after previous tests. At this point, the most useful next step would be to share your docker-compose.yml (with secrets removed) and the relevant environment variables, because the issue likely lives in configuration rather than worker count.
services:
n8n-redis:
container_name: n8n-redis
image: redis:latest
networks:
- n8n
env_file:
- n8n-redis.env
volumes:
- /home/docker/n8n/redis:/data
command: /bin/sh -c 'redis-server --requirepass "$${REDIS_PASSWORD}"'
healthcheck:
test: ["CMD-SHELL", "redis-cli -a \"$${REDIS_PASSWORD}\" ping | grep -q PONG"]
interval: 15s
timeout: 5s
retries: 5
start_period: 20s
restart: always
n8n-db:
container_name: n8n-db
image: postgres:18
networks:
- n8n
ports:
- 5432:5432
env_file:
- n8n-db.env
volumes:
- /home/docker/n8n/db:/var/lib/postgresql/data
healthcheck:
test:
- CMD-SHELL
- pg_isready
interval: 10s
start_period: 20s
restart: always
n8n:
container_name: n8n
image: docker.n8n.io/n8nio/n8n:next
networks:
- n8n
ports:
- 5678:5678
env_file:
- n8n.env
volumes:
- /home/docker/n8n:/home/node/.n8n
- truenas:/truenas
user: '1000'
depends_on:
n8n-db:
condition: service_healthy
n8n-redis:
condition: service_healthy
deploy:
resources:
limits:
cpus: 7
memory: 12GB
healthcheck:
test: ["CMD-SHELL", "node -e \"require('http').get('http://127.0.0.1:5678/healthz/readiness', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))\""]
interval: 30s
timeout: 10s
retries: 5
start_period: 40s
logging:
driver: json-file
options:
max-size: 50m
max-file: 3
restart: always
n8n-worker:
container_name: n8n-worker
image: docker.n8n.io/n8nio/n8n:next
networks:
- n8n
env_file:
- n8n-worker.env
volumes:
- /home/docker/n8n:/home/node/.n8n
- truenas:/truenas
user: '1000'
command: worker --concurrency=10
depends_on:
n8n-db:
condition: service_healthy
n8n:
condition: service_healthy
n8n-redis:
condition: service_healthy
deploy:
resources:
limits:
cpus: 7
memory: 12GB
healthcheck:
test: ["CMD-SHELL", "node -e \"require('http').get('http://127.0.0.1:5678/healthz/readiness', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))\""]
interval: 30s
timeout: 10s
retries: 5
start_period: 40s
logging:
driver: json-file
options:
max-size: 50m
max-file: 3
restart: always
n8n-runner:
container_name: n8n-runner
image: <ourgit>/it/docker/n8n-runners:20260326-pydeps1
networks:
- n8n
env_file:
- n8n-runner.env
volumes:
- /home/docker/n8n/runners/n8n-task-runners.json:/etc/n8n-task-runners.json
- truenas:/truenas
depends_on:
n8n-worker:
condition: service_healthy
n8n-db:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "node -e \"const s=require('net').connect({host:'127.0.0.1',port:5680},()=>{s.end();process.exit(0)});s.on('error',()=>process.exit(1));\""]
interval: 30s
timeout: 10s
retries: 5
start_period: 40s
logging:
driver: json-file
options:
max-size: 50m
max-file: 3
restart: always
networks:
n8n:
name: n8n
volumes:
truenas:
driver_opts:
type: nfs
o: addr=192.168.10.75,nolock,soft,nfsvers=4
device: :/mnt/gipsy/n8n
Do I need to send other configuration files to help with our problem?
@Alex.86
I’d start by replacing docker.n8n.io/n8nio/n8n:next with a pinned stable version on both main and worker (for example the same exact release tag). next changes frequently and isn’t ideal while debugging duplicate executions. I’d also fully recreate the stack after changing versions so no old containers or mixed images remain connected to Redis.