Every workflow starts with a trigger and does its work through action nodes. This lesson covers all trigger types and the most important core nodes.
| Trigger | When it fires | Best for |
|---|---|---|
| Manual | You click "Execute" | Testing, one-off runs |
| Schedule | Cron expression or interval | Daily reports, syncs, cleanups |
| Webhook | External HTTP request hits the URL | Form submissions, app events |
| App Event | Gmail, Slack, GitHub, etc. push an event | Real-time reactive automations |
| Form Trigger | Built-in n8n form is submitted | Quick internal forms |
The Schedule Trigger fires at a defined interval. You can use the visual picker (every X minutes/hours/days) or enter a cron expression for precise control.
┌───── minute (0-59) │ ┌───── hour (0-23) │ │ ┌───── day of month (1-31) │ │ │ ┌───── month (1-12) │ │ │ │ ┌───── day of week (0-6, Sun=0) │ │ │ │ │ * * * * *
0 9 * * * # Every day at 9:00 AM 0 9 * * 1 # Every Monday at 9:00 AM */15 * * * * # Every 15 minutes 0 0 1 * * # First day of every month 0 8,17 * * 1-5 # 8am and 5pm on weekdays
The Webhook Trigger gives you a unique URL. Any HTTP request to that URL starts the workflow. The request body, query string, and headers all become available as data.
# Test webhook with curl
curl -X POST https://your-n8n.io/webhook/abc123 \
-H "Content-Type: application/json" \
-d '{"name":"Alice","email":"alice@example.com"}'
# Access in workflow:
{{ $json.name }} # "Alice"
{{ $json.email }} # "alice@example.com"
{{ $json.headers["x-api-key"] }} # header value
| Node | Purpose | Key settings |
|---|---|---|
| HTTP Request | Call any REST API | Method, URL, auth, headers, body |
| Set | Add, edit, or remove fields on items | Field name, value, type |
| IF | Branch based on a condition | Condition, AND/OR logic |
| Switch | Multiple condition routes | Rules, output index |
| Merge | Combine data from multiple branches | Mode: Append, By Index, By Key |
| Code | Custom JavaScript logic | JS code, input items |
| Wait | Pause execution for time or webhook | Duration, resume webhook |
The IF node splits the workflow into two branches: true (condition met) and false (condition not met). Each branch continues independently.
# Condition examples:
{{ $json.score }} >= 70 # Number comparison
{{ $json.status }} equals "active" # String equals
{{ $json.email }} contains "@" # String contains
{{ $json.items.length }} > 0 # Array length check
Use Switch when you have more than two possible paths. Each rule maps to a numbered output connector.
# Example: Route by order status Rule 1: status equals "pending" → Output 0 Rule 2: status equals "paid" → Output 1 Rule 3: status equals "cancelled" → Output 2 Fallback → Output 3 (optional)
| Mode | Description | Use when |
|---|---|---|
| Append | All items from both inputs combined into one list | Combining two lists |
| Merge By Index | Pairs item 0 from input 1 with item 0 from input 2 | Parallel fetches of same records |
| Merge By Key | Matches items by a shared field value | Joining on ID or email |
| Keep Key Matches | Only outputs items found in both inputs | Inner join behaviour |
# GET request with query params
Method: GET
URL: https://api.example.com/users
Query Parameters:
page = 1
limit = 50
# POST with JSON body
Method: POST
URL: https://api.example.com/users
Body Content Type: JSON
Body:
{
"name": "{{ $json.name }}",
"email": "{{ $json.email }}"
}
# With Bearer token auth
Authentication: Header Auth
Name: Authorization
Value: Bearer YOUR_TOKEN_HERE
{{ $json.statusCode }} in the next node.