n8n-deployment
Skill0 starsChanged 10 months agoMITView on GitHub
Production deployment guide for n8n. Use when setting up n8n for production, scaling, configuring queue mode, or optimizing database.
In this repository9 other files it gives its agents.
- create-credentialsSkill
- monitor-executionsSkill
- n8n-diagnosticsSkill
- n8n-patternsSkill
- n8n-securitySkill
- n8n-testingSkill
- test-workflowSkill
- workflow-helpersSkill
- workflow-templatesSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 7 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 16
Not suitable for production
- Distinctive: line 189
Monitor Redis queue depth: - avoid >2-3 minute backups
- Distinctive: line 257
Use PgBouncer for connection pooling:
- Distinctive: line 419
Verify workers are running
- Distinctive: line 420
Check worker logs for errors
- Distinctive: line 425
Check database query performance
- Distinctive: line 428
Check external API latency
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
n8n Deployment Skill
This skill provides production deployment and scaling guidance for n8n.
Deployment Modes
Default Mode (Development Only)
- Single process
- SQLite database
- Not suitable for production
- Limited scalability
Queue Mode (Production)
- Multiple workers via Redis
- PostgreSQL database
- Horizontal scaling
- High availability
Queue Mode Setup
Architecture
┌─────────────┐
│ Redis │
│ (Queue) │
└──────┬──────┘
│
┌─────────────┐ ┌──────┴──────┐ ┌─────────────┐
│ Main │────▶│ Queue │────▶│ Worker 1 │
│ Instance │ │ │ └─────────────┘
│ (Triggers) │ │ │────▶│ Worker 2 │
└─────────────┘ │ │ └─────────────┘
│ │────▶│ Worker N │
└─────────────┘ └─────────────┘
│
┌──────┴──────┐
│ PostgreSQL │
│ (Database) │
└─────────────┘How It Works
- Main instance handles triggers (webhooks, schedules)
- Main instance generates execution ID, pushes to Redis
- Worker picks up job from Redis queue
- Worker fetches workflow from PostgreSQL
- Worker executes workflow
- Worker writes results to PostgreSQL
- Worker notifies Redis of completion
Environment Configuration
Main Instance:
# Execution mode
EXECUTIONS_MODE=queue
# Database (PostgreSQL required)
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD_FILE=/run/secrets/db_password
# Redis
QUEUE_BULL_REDIS_HOST=redis
QUEUE_BULL_REDIS_PORT=6379
# Main instance settings
N8N_RUNNERS_ENABLED=trueWorker Instance:
# Same database and Redis config as main
EXECUTIONS_MODE=queue
DB_TYPE=postgresdb
# ... same DB config ...
# Worker-specific
N8N_DISABLE_UI=true
N8N_LISTEN_ADDRESS=0.0.0.0Docker Compose Example
version: '3.8'
services:
postgres:
image: postgres:15
environment:
POSTGRES_DB: n8n
POSTGRES_USER: n8n
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
volumes:
- postgres_data:/var/lib/postgresql/data
secrets:
- db_password
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
n8n:
image: n8nio/n8n
environment:
- EXECUTIONS_MODE=queue
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD_FILE=/run/secrets/db_password
- QUEUE_BULL_REDIS_HOST=redis
ports:
- "5678:5678"
depends_on:
- postgres
- redis
secrets:
- db_password
n8n-worker:
image: n8nio/n8n
command: worker
environment:
- EXECUTIONS_MODE=queue
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD_FILE=/run/secrets/db_password
- QUEUE_BULL_REDIS_HOST=redis
depends_on:
- postgres
- redis
- n8n
secrets:
- db_password
deploy:
replicas: 3
volumes:
postgres_data:
redis_data:
secrets:
db_password:
file: ./secrets/db_password.txtStart Workers
# CLI
npx n8n worker --concurrency=10
# Docker
docker run n8nio/n8n worker --concurrency=10Scaling Guidelines
Worker Sizing
| Workload | Workers | Concurrency | Total Capacity |
| Light | 2 | 10 | 20 concurrent |
| Medium | 3-5 | 10 | 30-50 concurrent |
| Heavy | 5-10 | 5-10 | 25-100 concurrent |
| Enterprise | 10+ | 5 | 50+ concurrent |
Best Practices
- Fewer workers with more CPU > many small workers
- Start with 2-3 workers, scale based on metrics
- Monitor Redis queue depth - avoid >2-3 minute backups
- Avoid low concurrency + many workers - overloads DB
Scaling Triggers
Scale up when:
- Redis queue consistently >100 jobs
- Average wait time >30 seconds
- CPU >70% on workers
Scale down when:
- Queue consistently empty
- Workers idle >50% of time
- Cost optimization needed
Database Optimization
PostgreSQL Configuration
-- Recommended settings (postgresql.conf)
shared_buffers = 256MB # 25% of RAM
work_mem = 4MB
effective_cache_size = 768MB # 75% of RAM
maintenance_work_mem = 128MB
max_connections = 200Execution History Pruning
Auto-Pruning:
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=30 # days
EXECUTIONS_DATA_SAVE_ON_ERROR=all
EXECUTIONS_DATA_SAVE_ON_SUCCESS=none # for high volumeManual Pruning:
-- Delete executions older than 30 days
DELETE FROM execution_entity
WHERE finished_at < NOW() - INTERVAL '30 days';
-- Clean orphaned data
DELETE FROM execution_data
WHERE execution_id NOT IN (SELECT id FROM execution_entity);
-- Reclaim space
VACUUM FULL execution_entity, execution_data;Performance Indexes
-- Improve execution queries
CREATE INDEX CONCURRENTLY idx_execution_finished
ON execution_entity(finished_at);
CREATE INDEX CONCURRENTLY idx_execution_workflow
ON execution_entity(workflow_id, finished_at);
CREATE INDEX CONCURRENTLY idx_execution_status
ON execution_entity(status, finished_at);Connection Pooling
Use PgBouncer for connection pooling:
pgbouncer:
image: edoburu/pgbouncer
environment:
- DATABASE_URL=postgres://n8n:password@postgres:5432/n8n
- POOL_MODE=transaction
- MAX_CLIENT_CONN=1000
- DEFAULT_POOL_SIZE=50Monitoring Setup
Health Endpoints
| Endpoint | Purpose |
/healthz | Basic health check |
/healthz/readiness | Ready to accept traffic |
/metrics | Prometheus metrics |
Prometheus Metrics
# prometheus.yml
scrape_configs:
- job_name: 'n8n'
static_configs:
- targets: ['n8n:5678']
metrics_path: /metricsKey Metrics to Monitor
| Metric | Warning | Critical |
| Queue depth | >100 | >500 |
| Execution time (avg) | >30s | >120s |
| Error rate | >5% | >15% |
| Worker CPU | >70% | >90% |
| Database connections | >80% | >95% |
Grafana Dashboard
Monitor these panels:
- Workflow executions per minute
- Execution duration histogram
- Error rate by workflow
- Queue depth over time
- Worker utilization
High Availability
Multi-Region Setup
Region A Region B
┌─────────┐ ┌─────────┐
│ LB │ │ LB │
└────┬────┘ └────┬────┘
│ │
┌────┴────┐ ┌────┴────┐
│ n8n │ │ n8n │
│ (Main) │ │(Standby)│
└────┬────┘ └────┬────┘
│ │
└──────────┬───────────────┘
│
┌──────┴──────┐
│ PostgreSQL │
│ (Primary) │
└──────┬──────┘
│
┌──────┴──────┐
│ PostgreSQL │
│ (Replica) │
└─────────────┘Webhook Load Balancing
For high webhook volume:
nginx:
upstream n8n_webhooks {
least_conn;
server n8n-webhook-1:5678;
server n8n-webhook-2:5678;
server n8n-webhook-3:5678;
}
server {
location /webhook/ {
proxy_pass http://n8n_webhooks;
}
}Resource Limits
Memory Configuration
# Node.js heap size (match to container limit)
NODE_OPTIONS=--max-old-space-size=4096 # 4GB
# Container limits
docker run --memory=4g --memory-swap=4g n8nio/n8nTimeout Configuration
# Execution timeout (seconds)
EXECUTIONS_TIMEOUT=300
EXECUTIONS_TIMEOUT_MAX=7200
# Function node timeout (milliseconds)
N8N_NODE_FUNCTION_TIMEOUT=120000Production Checklist
Infrastructure
- PostgreSQL 13+ configured
- Redis for queue mode
- HTTPS with valid SSL
- Load balancer for webhooks
- Health checks configured
Performance
- Queue mode enabled
- Workers sized appropriately
- Database indexes created
- Connection pooling enabled
- Execution pruning configured
Monitoring
- Prometheus metrics exposed
- Grafana dashboards set up
- Alerts configured
- Log aggregation enabled
Security
- Secrets via
_FILEsuffix N8N_BLOCK_ENV_ACCESS_IN_NODE=true- HTTPS enforced
- Webhook authentication enabled
Backup & Recovery
- Database backups scheduled
- Workflow exports automated
- Disaster recovery plan documented
- Restore procedure tested
Troubleshooting
Queue Not Processing
- Check Redis connection
- Verify workers are running
- Check worker logs for errors
- Verify database connectivity
Slow Executions
- Check database query performance
- Review execution history size
- Monitor worker CPU/memory
- Check external API latency
Memory Issues
- Enable queue mode (isolates execution)
- Process data in batches
- Increase Node.js heap size
- Prune execution history
Remember: Production n8n requires queue mode. Never run default mode with production workloads.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

