// Automation Reference

n8n
Command Guide

$ nodes · expressions · tricks · workflow patterns

6
Categories
40+
Commands
Workflows
Core Basics
// fundamental concepts and getting started
workflow anatomy

How a Workflow Works

Every workflow starts with a Trigger node and flows data through connected Action nodes. Data passes between nodes as JSON arrays called "items".

1
Trigger — Webhook, Schedule, Manual, or App event starts the flow
2
Process — Set, Function, IF, or Merge nodes transform data
3
Output — Send to Slack, HTTP, DB, email, or any destination
triggeractionjson
data model

Understanding Items

n8n passes data as an array of items. Each item has a json property. Every node outputs items that the next node receives.

// Item structure from any node [ { "json": { "id": 42, "name": "Alice", "email": "alice@example.com" } }, { "json": { "id": 43, "name": "Bob" } } ]
trigger types

Trigger Node Types

Pick the right trigger for your automation context.

⏰ ScheduleCron-based
🌐 WebhookHTTP POST/GET
🖱️ ManualTest runs
📬 EmailIMAP polling
📦 App EventsSlack, GitHub…
credentials

Setting Up Credentials

Credentials are stored securely and reused across nodes. Never hardcode secrets in expressions.

1
Go to Settings → Credentials → Add new
2
Choose credential type (OAuth2, API Key, Basic Auth…)
3
Reference in any node via the credential dropdown
Tip: Use environment variables like {{$env.MY_API_KEY}} to inject secrets at runtime.
execution modes

Running Workflows

Three ways to execute — each suited for different scenarios.

▶️
Manual
Click "Execute Workflow" in editor. Best for testing.
⏱️
Scheduled
Cron trigger fires automatically on your schedule.
🔗
Webhook
External service POSTs to your unique webhook URL.
🧮
Expressions
// dynamic values using {{ }} syntax
access previous node

$json — Current Item Data

Access fields from the current item's JSON object inside any field using double curly braces.

// Get a field value {{ $json.email }} {{ $json["first name"] }} // spaces in keys // Nested objects {{ $json.user.address.city }} // Array element {{ $json.tags[0] }}
reference any node

$node — Get Data from Any Node

Pull data from a specific upstream node by referencing its name.

// Access by node name {{ $node["HTTP Request"].json.id }} {{ $node["Set"].json.status }} // Get first item from a node {{ $node["Fetch Users"].first().json.name }} // Get all items count {{ $node["Split"].all().length }}
built-in vars

Global Variables

n8n provides several built-in variables available everywhere.

$now // current DateTime object $today // today at midnight $itemIndex // current item index (0-based) $runIndex // current run count $workflow.id // workflow ID $env.VAR_NAME // environment variable $execution.id// unique execution ID
date & time

DateTime Expressions

n8n uses Luxon under the hood for date manipulation.

// Format current date {{ $now.toFormat('yyyy-MM-dd') }} {{ $now.toISO() }} // Add/subtract time {{ $now.plus({ days: 7 }).toISO() }} {{ $now.minus({ hours: 24 }).toFormat('HH:mm') }} // Parse a date string {{ DateTime.fromISO($json.date).weekdayLong }}
string helpers

String Manipulation

Use native JavaScript string methods directly inside expressions.

// Uppercase / lowercase {{ $json.name.toUpperCase() }} // Trim whitespace {{ $json.email.trim().toLowerCase() }} // Replace & split {{ $json.phone.replace(/-/g, '') }} {{ $json.tags.join(', ') }} // Ternary condition {{ $json.active ? 'Yes' : 'No' }}
fallbacks

Safe Access & Defaults

Prevent workflow crashes from missing or null values.

// Nullish coalescing (default value) {{ $json.nickname ?? 'Anonymous' }} // Optional chaining {{ $json?.address?.zip ?? 'N/A' }} // Check existence {{ $json.id !== undefined ? $json.id : 'missing' }}
Tip: Always use ?? on optional fields to avoid node failures on partial data.
🔧
Essential Nodes
// the nodes you'll use in every workflow
http request

HTTP Request Node

The workhorse for any REST API. Supports all HTTP methods, auth, headers, query params, and JSON bodies.

// Dynamic URL using expression URL: https://api.example.com/users/{{ $json.id }} // Body — JSON mode { "name": "{{ $json.name }}", "email": "{{ $json.email }}" } // Auth: select OAuth2 credential // Pagination: use "Split into items"
GETPOSTPUTDELETEOAuth2API Key
set node

Set Node — Transform Data

Rename, add, or overwrite fields on each item. Use "Keep Only Set" to strip unwanted fields.

// Common Set patterns // 1. Add computed field full_name: {{ $json.first + ' ' + $json.last }} // 2. Format date created_at: {{ $now.toISO() }} // 3. Rename field user_id: {{ $json.id }} // ✅ Toggle "Keep Only Set" = clean output
if / switch

IF & Switch — Branch Logic

Route items down different paths based on conditions. Switch handles multiple branches cleanly.

// IF Node — single condition Value 1: {{ $json.status }} Operation: Equal Value 2: "active" // Switch Node — multiple routes Value: {{ $json.priority }} Route 0: equals "high" → Urgent path Route 1: equals "medium" → Normal path Fallback: Low / default path
equalscontainsregexgreater than
split & merge

Split In Batches + Merge

Process large datasets in chunks and reassemble. Essential for APIs with rate limits.

// Split In Batches config Batch Size: 10 // items per run Options → Reset: false // Merge node — combine branches Mode: "Append" // stack all items Mode: "Merge By Index" // zip two arrays Mode: "Keep Key Matches" // inner join
Note: Always connect the Merge node after your loop completes, not inside it.
function node

Code Node (Function)

Full JavaScript execution. Return an array of items. Has access to all n8n variables.

// Process all items const results = []; for (const item of $input.all()) { results.push({ json: { ...item.json, score: item.json.value * 1.2, processed: true } }); } return results;
webhook

Webhook Node

Receive data from any external service via HTTP. Supports GET, POST, and custom responses.

// Your webhook URL (auto-generated) https://your-n8n.com/webhook/unique-id // Access incoming body {{ $json.body.event }} // Access query params {{ $json.query.token }} // Access headers {{ $json.headers["x-api-key"] }}
test URLprod URLrespond immediately
Pro Tricks
// tips that save hours of debugging
power trick

Pin Data for Testing

Pin output on any node so it always returns the same data during development — no live API calls needed while building downstream nodes.

1
Run the node once to get real data
2
Click the pin icon on the node output panel
3
Node now returns pinned data every run (shown in orange)
Tip: Unpin before activating to production — pinned data won't run live triggers.
error handling

Error Workflow Pattern

Attach an Error Trigger workflow to catch failures, send alerts, and log issues automatically.

// In Error Trigger workflow: {{ $json.execution.id }} // failed run ID {{ $json.execution.error.message }} // error text {{ $json.workflow.name }} // which workflow // → Send Slack/email alert with this info
deduplication

Deduplicate with $vars

Use workflow static variables to track processed IDs and skip already-seen records.

// Code Node — check & store seen IDs const seen = $vars.seenIds || []; const id = $json.id; if (seen.includes(id)) { return []; // skip this item } seen.push(id); $vars.seenIds = seen; return [{ json: $json }];
rate limiting

Rate Limit Requests

Add a Wait node between batches to respect API rate limits and avoid 429 errors.

// Wait node config Wait Amount: 1 Wait Unit: Seconds Resume: After time interval // Pattern: Split In Batches(10) → HTTP Request → Wait(1 second) // ← throttle → back to Split
Tip: Set batch size based on your API's rate limit (e.g. 60 req/min = 1 req/sec).
sub-workflows

Execute Workflow Node

Call another workflow as a function — great for reusable logic like sending formatted emails or syncing records.

// Parent workflow sends data to child Node: Execute Workflow Workflow: "Send Notification" Wait for completion: true // Child receives via "When Called By" // trigger and returns output items
transform trick

Flatten Nested Arrays

When an API returns nested arrays, use the Code node to flatten them into individual items.

// Flatten array-in-array return $input.first() .json.items .flat(2) .map(item => ({ json: item })); // Or explode with Item Lists node: // Field: "items" → splits 1 item → N items
🔁
Workflow Patterns
// proven recipes for common automation scenarios
pattern 01

Webhook → Process → Respond

Receive an HTTP request, process data synchronously, and return a JSON response to the caller.

1
Webhook — Response Mode: "Last Node"
2
Set / Code — transform incoming payload
3
Respond to Webhook — returns data as HTTP response
syncREST APIintegration
pattern 02

Schedule → Fetch → Notify

Periodic job that pulls data from an API and sends a formatted report to Slack or email.

1
1
Cron Trigger — e.g. every day at 9AM
2
HTTP Request — GET data from API
3
Set — format the message body
4
Slack / Email — send the notification
daily reportmonitoring
pattern 03

Paginated API Fetch

Loop through all pages of a paginated API until no more pages remain.

// HTTP Request → Pagination settings Pagination: Cursor-based OR offset Next Cursor: {{ $json.next_cursor }} Complete When: cursor is empty // OR manual loop pattern: // Set(page=1) → HTTP → IF(hasMore) // true → increment page → loop back // false → Merge all → done
pattern 04

Two-Way Sync Between Apps

Keep records in two systems in sync using upsert logic — update if exists, create if not.

1
Trigger — source app event (new/updated record)
2
HTTP GET — search for record in destination
3
IF — does destination record exist?
4
True → PATCH / False → POST to destination
pattern 05

AI Enrichment Pipeline

Feed items through an AI node (OpenAI/Claude) to classify, summarize, or extract data, then route by AI output.

// OpenAI node prompt System: "Classify as: support/sales/spam" User: {{ $json.email_body }} // Parse AI response {{ $json.message.content.trim().toLowerCase() }} // Switch node routes to correct queue
AIclassificationenrichment
pattern 06

Retry on Failure

Wrap unreliable nodes in a retry loop with exponential backoff to handle transient errors gracefully.

// On any node: Settings tab On Error: "Continue (using error output)" Retry On Fail: true Max Tries: 3 Wait Between Tries: 1000ms // Or handle in Code node: try { ... } catch (e) { return [{ json: { error: e.message } }]; }
⌨️
Keyboard Shortcuts
// move faster in the editor
canvas

Canvas Navigation

Execute workflowCtrl + Enter
Save workflowCtrl + S
Add nodeTab
UndoCtrl + Z
RedoCtrl + Shift + Z
Select all nodesCtrl + A
Zoom to fitCtrl + Shift + F
Reset zoomCtrl + 0
nodes

Node Interactions

Open nodeEnter or double-click
Delete nodeDelete / Backspace
Duplicate nodeCtrl + D
Copy nodeCtrl + C
Paste nodeCtrl + V
Disable nodeD (while selected)
Close panelEsc
Move canvasMiddle-click drag
quick tips

Editor Tricks

Search nodes fast: Press Tab on canvas and start typing the node name immediately.
Multi-select: Hold Shift and click to select multiple nodes — then move or delete in bulk.
Copy workflows: Select all → Ctrl+C → paste into another workflow or share as JSON text.