Production-ready Docker Compose configurations for n8n with PostgreSQL, optimized for different hardware specifications. Each configuration includes strict resource limits to prevent system instability and ensure predictable performance.
✨ Updated for n8n 1.117.3 with Task Runners support for secure Code node execution.
These configurations are built on four core principles:
- Strict Resource Limits: CPU and RAM are explicitly divided between services to prevent resource starvation
- Controlled Concurrency: Hard limits on parallel workflow executions prevent CPU overload
- Efficiency Over Quantity: Fewer workers with higher concurrency outperform many workers with low concurrency
- Secure Code Execution: Task runners provide isolated, secure execution for JavaScript and Python code
Path: 1vcpu-4gb-main-mode/
- Architecture: Single n8n instance with internal task runners
- Best for: Small deployments, development, testing
- Concurrency: 5 parallel workflows
- Task Runners: Internal mode (no extra container)
- Resource allocation:
- PostgreSQL: 0.5 vCPU + 2 GB RAM
- n8n: 0.5 vCPU + 2 GB RAM
- Total: 1 vCPU + 4 GB RAM (full utilization)
Path: 2vcpu-8gb/
Single Instance Mode (main-mode/)
- Architecture: Single n8n instance with internal task runners
- Best for: Moderate workloads, simpler setup
- Concurrency: 10 parallel workflows
- Task Runners: Internal mode (no extra container)
- Resource allocation:
- PostgreSQL: 1 vCPU + 4 GB RAM
- n8n: 1 vCPU + 4 GB RAM
- Total: 2 vCPU + 8 GB RAM (full utilization)
Queue Mode (queue-mode/)
- Architecture: 1 main + 1 worker + Redis + task-runners
- Best for: Better separation of concerns, webhook reliability
- Concurrency: 8 per worker
- Task Runners: External mode (sidecar container)
- Resource allocation:
- PostgreSQL: 0.7 vCPU + 3 GB RAM
- Redis: 0.2 vCPU + 512 MB RAM
- n8n-main: 0.4 vCPU + 1.5 GB RAM
- n8n-worker: 0.5 vCPU + 2.5 GB RAM
- task-runners: 0.2 vCPU + 512 MB RAM
- Total: 2 vCPU + 8 GB RAM (full utilization)
Path: 4vcpu-16gb/
Single Instance Mode (main-mode/)
- Architecture: Single n8n instance with internal task runners
- Best for: High workloads without queue complexity
- Concurrency: 20 parallel workflows
- Task Runners: Internal mode (no extra container)
- Resource allocation:
- PostgreSQL: 2 vCPU + 7 GB RAM
- n8n: 2 vCPU + 9 GB RAM
- Total: 4 vCPU + 16 GB RAM
Queue Mode - 2 Workers (queue-mode/2-workers/) ⭐ RECOMMENDED
- Architecture: 1 main + 2 workers + Redis + task-runners
- Best for: Maximum performance and stability
- Concurrency: 12 per worker (24 total)
- Task Runners: External mode (sidecar container)
- Resource allocation:
- PostgreSQL: 1.5 vCPU + 6.5 GB RAM
- Redis: 0.2 vCPU + 512 MB RAM
- n8n-main: 0.5 vCPU + 2 GB RAM
- n8n-worker-1: 0.8 vCPU + 3.5 GB RAM
- n8n-worker-2: 0.8 vCPU + 3.5 GB RAM
- task-runners: 0.2 vCPU + 512 MB RAM
- Total: 4 vCPU + 16 GB RAM (full utilization)
Queue Mode - 3 Workers (queue-mode/3-workers/) ⚠️ NOT RECOMMENDED
- Architecture: 1 main + 3 workers + Redis + task-runners
- Best for: Only if 2-workers are constantly at 100% CPU (rare)
- Concurrency: 10 per worker (30 total)
- Task Runners: External mode (sidecar container)
- Resource allocation:
- PostgreSQL: 1.4 vCPU + 6.5 GB RAM
- Redis: 0.2 vCPU + 512 MB RAM
- n8n-main: 0.4 vCPU + 1.5 GB RAM
- n8n-worker-1: 0.6 vCPU + 2.5 GB RAM
- n8n-worker-2: 0.6 vCPU + 2.5 GB RAM
- n8n-worker-3: 0.6 vCPU + 2.5 GB RAM
- task-runners: 0.2 vCPU + 512 MB RAM
- Total: 4 vCPU + 16 GB RAM (full utilization)
Select the configuration that matches your hardware:
cd 2vcpu-8gb/queue-mode/Copy and edit the .env file (or dockploy-environment-settings.env):
# Generate encryption key
openssl rand -base64 32
# Generate database password
openssl rand -base64 64Required variables:
N8N_HOST=n8n.yourdomain.com
N8N_ENCRYPTION_KEY=your_generated_key_here
POSTGRES_PASSWORD=your_generated_password_here
POSTGRES_USER=n8n
POSTGRES_DB=n8n
GENERIC_TIMEZONE=Europe/Paris
# For queue mode only (external task runners)
N8N_RUNNERS_AUTH_TOKEN=your_generated_token_heredocker-compose up -d# Check all services are running
docker-compose ps
# Check logs
docker-compose logs -f n8nTask runners provide secure, isolated execution for JavaScript and Python code in the Code node. They prevent malicious or buggy code from affecting your n8n instance.
- Used in: All single instance (main mode) configurations
- How it works: n8n launches task runners as child processes
- Pros: Simple, no extra containers, lower overhead
- Cons: Shares resources with n8n process
- Best for: 1-2 vCPU systems, development, testing
- Used in: All queue mode configurations
- How it works: Separate
task-runnerscontainer (sidecar) - Pros: Better isolation, independent scaling, more secure
- Cons: Extra container overhead
- Best for: Production queue mode deployments
Task runners are pre-configured in all docker-compose files. For queue mode, you need to set:
N8N_RUNNERS_AUTH_TOKEN=your_secure_token_hereGenerate with: openssl rand -base64 32
Check if task runners are active:
# Check n8n logs for task runner registration
docker-compose logs n8n | grep -i "runner"
# You should see: "Registered runner 'JS Task Runner'"Based on real-world testing, 2 workers with high concurrency outperform 8 workers with low concurrency by 63%.
The Problem with Many Workers:
- More database lock contention
- More connection overhead
- Workers spend time waiting for each other
- Database becomes the bottleneck
The Solution:
- Fewer workers (2-3 maximum)
- Higher concurrency per worker (10-15)
- Efficient connection reuse
- Less database contention
2 Workers at Concurrency 15:
- Connections used: ~16-24
- Connections available: ~270+ (out of 300)
- Plenty of room for traffic spikes
8 Workers at Concurrency 5:
- Connections used: ~48-64
- Connections available: ~30-50
- One spike and you're done
Only add more workers if:
- ✅ Current workers are at 100% CPU constantly
- ✅ Redis queue depth consistently > 50
- ✅ Database is NOT the bottleneck (< 70% CPU)
- ✅ You've monitored for several days
SELECT count(*) FROM pg_stat_activity;Should stay under 50 with 2 workers.
docker exec -it <redis-container> redis-cli LLEN bull:n8n:jobs:waitingShould stay under 50. If consistently higher, increase concurrency (not workers).
In n8n UI: Settings > Workers
- Shows active workers and their status
- Monitor execution times (should be consistent)
docker statsMonitor CPU and memory usage of each container.
Why: More workers = more database contention = slower performance
Why: Better connection reuse = better performance
Why: Inefficient database connection usage
Why: Optimal balance between throughput and stability
Why: Database locks become a major bottleneck
Why: Best performance-to-stability ratio
- Never commit
.envfiles - Use.env.exampleinstead - Backup your encryption key - Store it securely offline (you cannot recover credentials without it!)
- Use strong passwords - Generate with
openssl rand -base64 64 - Secure task runners - Generate unique
N8N_RUNNERS_AUTH_TOKENfor queue mode - Enable HTTPS - Use a reverse proxy (Nginx/Traefik/Dokploy)
- Regular backups - Backup PostgreSQL and n8n volumes
- Environment variable access - Set
N8N_BLOCK_ENV_ACCESS_IN_NODE=trueif you don't need env vars in Code nodes - Git node security -
N8N_GIT_NODE_DISABLE_BARE_REPOS=trueis enabled by default
# Backup PostgreSQL
docker exec <postgres-container> pg_dump -U n8n n8n > backup.sql
# Backup n8n data
docker run --rm -v n8n_data:/data -v $(pwd):/backup alpine tar czf /backup/n8n-data.tar.gz /data# Restore PostgreSQL
docker exec -i <postgres-container> psql -U n8n n8n < backup.sql
# Restore n8n data
docker run --rm -v n8n_data:/data -v $(pwd):/backup alpine tar xzf /backup/n8n-data.tar.gz -C /Solution: Increase max_connections in PostgreSQL or reduce worker concurrency.
Check:
- All workers use the same
N8N_ENCRYPTION_KEY - Redis is accessible from all workers
- PostgreSQL is accessible from all workers
Check:
N8N_RUNNERS_AUTH_TOKENis set and identical in n8n-main and task-runners- Task runners can reach n8n-main on port 5679
- Check logs:
docker-compose logs task-runners
Check:
- Task runners are registered (check n8n logs for "Registered runner")
- For external mode: task-runners container is running
- Check task runner logs for errors
Solution: Reduce concurrency or add more RAM. Check for memory-heavy workflow nodes.
Check:
- Database CPU usage (should be < 70%)
- Number of database connections (should be < 50)
- Redis queue depth (should be < 50)
Solution: These configurations are updated for n8n 1.117.3. Old variables like EXECUTIONS_PROCESS=main and EXECUTIONS_MODE=queue have been removed.
- n8n Official Documentation
- n8n Task Runners Documentation
- n8n Queue Mode Guide
- n8n Environment Variables
- PostgreSQL Connection Pooling
- Docker Compose Documentation
- Dokploy Documentation (if using Dokploy)
Contributions are welcome! Please:
- Test your changes thoroughly
- Update documentation
- Follow the existing configuration style
- Include resource allocation details
MIT License - Feel free to use and modify for your needs.
- ✅ Updated for n8n 1.117.3
- ✅ Added Task Runners support (internal and external modes)
- ✅ Removed deprecated environment variables (
EXECUTIONS_PROCESS,EXECUTIONS_MODE) - ✅ Added security variables (
N8N_BLOCK_ENV_ACCESS_IN_NODE,N8N_GIT_NODE_DISABLE_BARE_REPOS) - ✅ Optimized worker concurrency for better stability
- ✅ Added task-runners sidecar containers for queue mode
- ✅ Updated documentation with task runners information
- Initial production-ready configurations
- Resource limits for 1, 2, and 4 vCPU systems
- Main and queue mode variants
These configurations are based on:
- Real-world production testing
- n8n community best practices
- Performance optimization research
- Database scaling principles
- n8n 1.117.3 official documentation
- n8n team for the excellent workflow automation platform
- Community members who shared their production experiences
- Contributors who helped test and improve these configurations
Need help? Open an issue with:
- Your hardware specs
- Current configuration
- Observed behavior
- Expected behavior
- n8n version