n8n
n8n workflow automation cheat sheet with nodes, expressions, triggers, code patterns, error handling, and self-hosting deployment tips.
Core Concepts
Basic building blocks of n8n automation
# Workflow Structure
- Workflows: Visual automation sequences
- Trigger Nodes: Start workflow (webhook, schedule, app event)
- Action Nodes: Perform operations (HTTP, Code, Transform)
# Data Format (Items)
[
{ json: { id: 1, name: "Alice" } },
{ json: { id: 2, name: "Bob" } }
]Managing authentication for external services
# Credential Types
- OAuth2: Auto token refresh (Authorization Code, Client Credentials)
- API Key: Header Auth, Query Param, Custom Header
- Basic Auth: Username + Password (Base64 encoded)
- JWT: JSON Web Token validation
# Common Auth Headers
Authorization: Bearer TOKEN
X-API-Key: YOUR_KEYExpression Syntax
Expression variables for accessing workflow data
# Current Item Data (inline expressions)
{{ $json.user.email }}
{{ $json['order']['items'][0]['name'] }}
# Reference Other Nodes
{{ $node["Node Name"].json.field }}
{{ $('Node Name').item.json.field }}
{{ $('HTTP Request').all() }} // All items
# Workflow & Execution Metadata
{{ $workflow.id }}
{{ $workflow.name }}
{{ $execution.id }}
{{ $execution.mode }} // 'manual', 'trigger', 'webhook'Built-in date/time manipulation using Luxon
# Current Time
{{ $now.toISO() }} // 2024-01-15T14:30:00.000Z
{{ $now.toFormat('yyyy-MM-dd') }} // 2024-01-15
{{ $today.toISO() }} // Midnight today
# Date Arithmetic
{{ $now.plus({ days: 7 }).toISO() }} // 7 days from now
{{ $now.minus({ hours: 2 }) }} // 2 hours ago
# Parsing & Formatting
{{ '2024-01-15'.toDateTime('yyyy-MM-dd') }}
{{ $now.toFormat('MMMM dd, yyyy') }} // January 15, 2024
{{ $now.toRelative() }} // "2 hours ago"String, array, and object manipulation in expressions
# String Methods
{{ $json.email.toLowerCase() }}
{{ $json.name.trim() }}
{{ $json.text.replace('old', 'new') }}
# Array Methods
{{ $json.tags.join(', ') }}
{{ $json.items.length }}
{{ $json.prices.map(p => p * 1.1) }}
# JMESPath Queries
{{ $json.jmespath('users[0].email') }}
{{ $json.jmespath('users[*].email') }}
{{ $json.jmespath('users[?age > \`18\`].name') }}Essential Nodes
Make API calls to any service
# Basic GET Request
Method: GET
URL: https://api.example.com/users
# POST with JSON Body
Method: POST
URL: https://api.example.com/users
Body Content Type: JSON
Body: { "name": "John", "email": "john@example.com" }
# With Authentication
Authentication: Predefined Credential Type
Credential Type: Header Auth
Header Auth: X-API-Key = your-keyConditional branching in workflows
# IF Node (Two-way branching)
Condition: {{ $json.status }} equals "active"
- True branch → Process active items
- False branch → Handle inactive
# Switch Node (Multi-way routing)
Mode: Rules
Rule 1: {{ $json.type }} equals "order" → Order path
Rule 2: {{ $json.type }} equals "refund" → Refund path
Fallback → Default pathTransform and reshape data structure
# Add/Modify Fields
Mode: Manual Mapping
Fields to Set:
fullName: {{ $json.first }} {{ $json.last }}
email: {{ $json.email.toLowerCase() }}
processed: true
# Important Setting!
Include Other Input Fields: Yes (or data gets lost!)Combine data from multiple sources
# Merge Node Modes
- Append: Combine all items into one list
- Merge By Fields: Join by matching key (like SQL JOIN)
- Merge By Position: Combine by array index
- Multiplex: Cartesian product
- SQL Query: Custom SQL (v1.49.0+)
# Aggregate Node
Operation: Aggregate Individual Fields
Fields: items (creates array from all items)Code Node
Common code patterns for data transformation
// Run Once for All Items (default)
const items = $input.all();
return items.map(item => ({
json: {
email: item.json.email.toLowerCase(),
fullName: \`\${item.json.first} \${item.json.last}\`,
total: item.json.price * item.json.quantity
}
}));Persist data between executions
// Get/Set Workflow Static Data
const staticData = getWorkflowStaticData('global');
// Read last processed ID
const lastId = staticData.lastProcessedId || 0;
// Update for next execution
staticData.lastProcessedId = currentId;
// Node-specific static data
const nodeData = getWorkflowStaticData('node');
nodeData.retryCount = (nodeData.retryCount || 0) + 1;Triggers
HTTP endpoints for external events
# Webhook Configuration
HTTP Method: POST
Path: my-webhook
Authentication: Header Auth
Header Name: X-API-Key
Header Value: your-secret-key
# URLs
Test: https://your-n8n.com/webhook-test/my-webhook
Production: https://your-n8n.com/webhook/my-webhookCron-based workflow scheduling
# Common Schedules
Every 5 minutes: */5 * * * *
Hourly at :00: 0 * * * *
Daily at 9 AM: 0 9 * * *
Weekdays 9 AM: 0 9 * * 1-5
Monthly 1st: 0 0 1 * *
# Cron Format
* * * * *
│ │ │ │ └─ Day of Week (0-7, Sun=0 or 7)
│ │ │ └─── Month (1-12)
│ │ └───── Day of Month (1-31)
│ └─────── Hour (0-23)
└───────── Minute (0-59)Error Handling
Strategies for handling workflow errors
# Node-Level Settings
Settings Tab:
Retry On Fail: Yes
Max Tries: 3
Wait Between Tries: 1000ms
Continue On Fail: Yes (for non-critical operations)
# Error Output (Red Connector)
Connect red output → Slack notification
Connect red output → Log to databaseSelf-Hosting
Run n8n with Docker and Docker Compose
# Quick Start (Docker)
docker run -it --rm \
--name n8n \
-p 5678:5678 \
-v ~/.n8n:/home/node/.n8n \
n8nio/n8n
# Access at http://localhost:5678Essential configuration for self-hosted n8n
# Core Settings
N8N_HOST=n8n.yourcompany.com
N8N_PORT=5678
N8N_PROTOCOL=https
WEBHOOK_URL=https://n8n.yourcompany.com/
# Timezone
TZ=America/New_York
GENERIC_TIMEZONE=America/New_York
## Security
# Basic auth (N8N_BASIC_AUTH_*) is removed in v2. Create an owner
# account on first launch (user management) and run behind HTTPS.
N8N_ENCRYPTION_KEY=your-random-32-char-key
# Generate with: openssl rand -hex 32Scaling & Performance
Scale n8n with workers and Redis
# Architecture
Main Instance: UI, API, triggers, webhook reception
Workers: Execute workflows from queue
Redis: Message broker (Bull queue)
PostgreSQL: Required (SQLite not supported)
# Main Instance
EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis
# Worker Instance
docker run n8nio/n8n worker --concurrency=10Optimize workflow performance
# Batch Processing
Use Split In Batches node for large datasets
Process 100 items at a time instead of 10,000
# Rate Limiting
Add Wait node between API calls (1-2 seconds)
Prevents 429 Too Many Requests errors
# Binary Data
N8N_DEFAULT_BINARY_DATA_MODE=filesystem
Use S3 for large files in queue mode
# Incremental Processing
Store last ID in static data
Query only new records: WHERE id > lastIdCommon Gotchas
Common pitfalls and how to fix them
# Edit Fields Overwrites Data
❌ Problem: All input fields disappear
✅ Fix: Enable "Include Other Input Fields"
# Code Node Return Format
❌ Wrong: return { result: 'success' }
✅ Right: return { json: { result: 'success' } }
# Merge Executes Both IF Paths
❌ Problem: Both true and false paths run
✅ Understand: Merge triggers all waiting inputs
# Static Data Not Persisting
❌ Problem: Data lost between runs
✅ Note: Only saves in PRODUCTION executions!AI Features
Build AI-powered workflows with LLMs
# AI Agent Node
- Root node for autonomous AI decisions
- Powered by LLMs (OpenAI, Claude, Gemini, etc.)
- Can select tools, maintain conversation context
- Native LangChain integration
# Supported LLMs
- OpenAI (GPT-4, GPT-3.5)
- Anthropic (Claude 3)
- Google (Gemini, Vertex AI)
- Groq (Llama, Mixtral)
- Ollama (local LLMs)