Files
gh-czlonkowski-n8n-skills/skills/n8n-node-configuration/OPERATION_PATTERNS.md
2025-11-29 18:17:17 +08:00

15 KiB

Operation Patterns Guide

Common node configuration patterns organized by node type and operation.


Overview

Purpose: Quick reference for common node configurations

Coverage: Top 20 most-used nodes from 525 available

Pattern format:

  • Minimal valid configuration
  • Common options
  • Real-world examples
  • Gotchas and tips

HTTP & API Nodes

HTTP Request (nodes-base.httpRequest)

Most versatile node for HTTP operations

GET Request

Minimal:

{
  "method": "GET",
  "url": "https://api.example.com/users",
  "authentication": "none"
}

With query parameters:

{
  "method": "GET",
  "url": "https://api.example.com/users",
  "authentication": "none",
  "sendQuery": true,
  "queryParameters": {
    "parameters": [
      {
        "name": "limit",
        "value": "100"
      },
      {
        "name": "offset",
        "value": "={{$json.offset}}"
      }
    ]
  }
}

With authentication:

{
  "method": "GET",
  "url": "https://api.example.com/users",
  "authentication": "predefinedCredentialType",
  "nodeCredentialType": "httpHeaderAuth"
}

POST with JSON

Minimal:

{
  "method": "POST",
  "url": "https://api.example.com/users",
  "authentication": "none",
  "sendBody": true,
  "body": {
    "contentType": "json",
    "content": {
      "name": "John Doe",
      "email": "john@example.com"
    }
  }
}

With expressions:

{
  "method": "POST",
  "url": "https://api.example.com/users",
  "authentication": "none",
  "sendBody": true,
  "body": {
    "contentType": "json",
    "content": {
      "name": "={{$json.name}}",
      "email": "={{$json.email}}",
      "metadata": {
        "source": "n8n",
        "timestamp": "={{$now.toISO()}}"
      }
    }
  }
}

Gotcha: Remember sendBody: true for POST/PUT/PATCH!

PUT/PATCH Request

Pattern: Same as POST, but method changes

{
  "method": "PUT",  // or "PATCH"
  "url": "https://api.example.com/users/123",
  "authentication": "none",
  "sendBody": true,
  "body": {
    "contentType": "json",
    "content": {
      "name": "Updated Name"
    }
  }
}

DELETE Request

Minimal (no body):

{
  "method": "DELETE",
  "url": "https://api.example.com/users/123",
  "authentication": "none"
}

With body (some APIs allow):

{
  "method": "DELETE",
  "url": "https://api.example.com/users",
  "authentication": "none",
  "sendBody": true,
  "body": {
    "contentType": "json",
    "content": {
      "ids": ["123", "456"]
    }
  }
}

Webhook (nodes-base.webhook)

Most common trigger - 813 searches!

Basic Webhook

Minimal:

{
  "path": "my-webhook",
  "httpMethod": "POST",
  "responseMode": "onReceived"
}

Gotcha: Webhook data is under $json.body, not $json!

// ❌ Wrong
{
  "text": "={{$json.email}}"
}

// ✅ Correct
{
  "text": "={{$json.body.email}}"
}

Webhook with Authentication

Header auth:

{
  "path": "secure-webhook",
  "httpMethod": "POST",
  "responseMode": "onReceived",
  "authentication": "headerAuth",
  "options": {
    "responseCode": 200,
    "responseData": "{\n  \"success\": true\n}"
  }
}

Webhook Returning Data

Custom response:

{
  "path": "my-webhook",
  "httpMethod": "POST",
  "responseMode": "lastNode",  // Return data from last node
  "options": {
    "responseCode": 201,
    "responseHeaders": {
      "entries": [
        {
          "name": "Content-Type",
          "value": "application/json"
        }
      ]
    }
  }
}

Communication Nodes

Slack (nodes-base.slack)

Popular choice for AI agent workflows

Post Message

Minimal:

{
  "resource": "message",
  "operation": "post",
  "channel": "#general",
  "text": "Hello from n8n!"
}

With dynamic content:

{
  "resource": "message",
  "operation": "post",
  "channel": "={{$json.channel}}",
  "text": "New user: {{$json.name}} ({{$json.email}})"
}

With attachments:

{
  "resource": "message",
  "operation": "post",
  "channel": "#alerts",
  "text": "Error Alert",
  "attachments": [
    {
      "color": "#ff0000",
      "fields": [
        {
          "title": "Error Type",
          "value": "={{$json.errorType}}"
        },
        {
          "title": "Timestamp",
          "value": "={{$now.toLocaleString()}}"
        }
      ]
    }
  ]
}

Gotcha: Channel must start with # for public channels or be a channel ID!

Update Message

Minimal:

{
  "resource": "message",
  "operation": "update",
  "messageId": "1234567890.123456",  // From previous message post
  "text": "Updated message content"
}

Note: messageId required, channel optional (can be inferred)

Create Channel

Minimal:

{
  "resource": "channel",
  "operation": "create",
  "name": "new-project-channel",  // Lowercase, no spaces
  "isPrivate": false
}

Gotcha: Channel name must be lowercase, no spaces, 1-80 chars!


Gmail (nodes-base.gmail)

Popular for email automation

Send Email

Minimal:

{
  "resource": "message",
  "operation": "send",
  "to": "user@example.com",
  "subject": "Hello from n8n",
  "message": "This is the email body"
}

With dynamic content:

{
  "resource": "message",
  "operation": "send",
  "to": "={{$json.email}}",
  "subject": "Order Confirmation #{{$json.orderId}}",
  "message": "Dear {{$json.name}},\n\nYour order has been confirmed.\n\nThank you!",
  "options": {
    "ccList": "admin@example.com",
    "replyTo": "support@example.com"
  }
}

Get Email

Minimal:

{
  "resource": "message",
  "operation": "getAll",
  "returnAll": false,
  "limit": 10
}

With filters:

{
  "resource": "message",
  "operation": "getAll",
  "returnAll": false,
  "limit": 50,
  "filters": {
    "q": "is:unread from:important@example.com",
    "labelIds": ["INBOX"]
  }
}

Database Nodes

Postgres (nodes-base.postgres)

Database operations - 456 templates

Execute Query

Minimal (SELECT):

{
  "operation": "executeQuery",
  "query": "SELECT * FROM users WHERE active = true LIMIT 100"
}

With parameters (SQL injection prevention):

{
  "operation": "executeQuery",
  "query": "SELECT * FROM users WHERE email = $1 AND active = $2",
  "additionalFields": {
    "mode": "list",
    "queryParameters": "user@example.com,true"
  }
}

Gotcha: ALWAYS use parameterized queries for user input!

// ❌ BAD - SQL injection risk!
{
  "query": "SELECT * FROM users WHERE email = '{{$json.email}}'"
}

// ✅ GOOD - Parameterized
{
  "query": "SELECT * FROM users WHERE email = $1",
  "additionalFields": {
    "mode": "list",
    "queryParameters": "={{$json.email}}"
  }
}

Insert

Minimal:

{
  "operation": "insert",
  "table": "users",
  "columns": "name,email,created_at",
  "additionalFields": {
    "mode": "list",
    "queryParameters": "John Doe,john@example.com,NOW()"
  }
}

With expressions:

{
  "operation": "insert",
  "table": "users",
  "columns": "name,email,metadata",
  "additionalFields": {
    "mode": "list",
    "queryParameters": "={{$json.name}},={{$json.email}},{{JSON.stringify($json)}}"
  }
}

Update

Minimal:

{
  "operation": "update",
  "table": "users",
  "updateKey": "id",
  "columns": "name,email",
  "additionalFields": {
    "mode": "list",
    "queryParameters": "={{$json.id}},Updated Name,newemail@example.com"
  }
}

Data Transformation Nodes

Set (nodes-base.set)

Most used transformation - 68% of workflows!

Set Fixed Values

Minimal:

{
  "mode": "manual",
  "duplicateItem": false,
  "assignments": {
    "assignments": [
      {
        "name": "status",
        "value": "active",
        "type": "string"
      },
      {
        "name": "count",
        "value": 100,
        "type": "number"
      }
    ]
  }
}

Set from Input Data

Mapping data:

{
  "mode": "manual",
  "duplicateItem": false,
  "assignments": {
    "assignments": [
      {
        "name": "fullName",
        "value": "={{$json.firstName}} {{$json.lastName}}",
        "type": "string"
      },
      {
        "name": "email",
        "value": "={{$json.email.toLowerCase()}}",
        "type": "string"
      },
      {
        "name": "timestamp",
        "value": "={{$now.toISO()}}",
        "type": "string"
      }
    ]
  }
}

Gotcha: Use correct type for each field!

// ❌ Wrong type
{
  "name": "age",
  "value": "25",      // String
  "type": "string"    // Will be string "25"
}

// ✅ Correct type
{
  "name": "age",
  "value": 25,        // Number
  "type": "number"    // Will be number 25
}

Code (nodes-base.code)

JavaScript execution - 42% of workflows

Simple Transformation

Minimal:

{
  "mode": "runOnceForAllItems",
  "jsCode": "return $input.all().map(item => ({\n  json: {\n    name: item.json.name.toUpperCase(),\n    email: item.json.email\n  }\n}));"
}

Per-item processing:

{
  "mode": "runOnceForEachItem",
  "jsCode": "// Process each item\nconst data = $input.item.json;\n\nreturn {\n  json: {\n    fullName: `${data.firstName} ${data.lastName}`,\n    email: data.email.toLowerCase(),\n    timestamp: new Date().toISOString()\n  }\n};"
}

Gotcha: In Code nodes, use $input.item.json or $input.all(), NOT {{...}}!

// ❌ Wrong - expressions don't work in Code nodes
{
  "jsCode": "const name = '={{$json.name}}';"
}

// ✅ Correct - direct access
{
  "jsCode": "const name = $input.item.json.name;"
}

Conditional Nodes

IF (nodes-base.if)

Conditional logic - 38% of workflows

String Comparison

Equals (binary):

{
  "conditions": {
    "string": [
      {
        "value1": "={{$json.status}}",
        "operation": "equals",
        "value2": "active"
      }
    ]
  }
}

Contains (binary):

{
  "conditions": {
    "string": [
      {
        "value1": "={{$json.email}}",
        "operation": "contains",
        "value2": "@example.com"
      }
    ]
  }
}

isEmpty (unary):

{
  "conditions": {
    "string": [
      {
        "value1": "={{$json.email}}",
        "operation": "isEmpty"
        // No value2 - unary operator
        // singleValue: true added by auto-sanitization
      }
    ]
  }
}

Gotcha: Unary operators (isEmpty, isNotEmpty) don't need value2!

Number Comparison

Greater than:

{
  "conditions": {
    "number": [
      {
        "value1": "={{$json.age}}",
        "operation": "larger",
        "value2": 18
      }
    ]
  }
}

Boolean Comparison

Is true:

{
  "conditions": {
    "boolean": [
      {
        "value1": "={{$json.isActive}}",
        "operation": "true"
        // Unary - no value2
      }
    ]
  }
}

Multiple Conditions (AND)

All must match:

{
  "conditions": {
    "string": [
      {
        "value1": "={{$json.status}}",
        "operation": "equals",
        "value2": "active"
      }
    ],
    "number": [
      {
        "value1": "={{$json.age}}",
        "operation": "larger",
        "value2": 18
      }
    ]
  },
  "combineOperation": "all"  // AND logic
}

Multiple Conditions (OR)

Any can match:

{
  "conditions": {
    "string": [
      {
        "value1": "={{$json.status}}",
        "operation": "equals",
        "value2": "active"
      },
      {
        "value1": "={{$json.status}}",
        "operation": "equals",
        "value2": "pending"
      }
    ]
  },
  "combineOperation": "any"  // OR logic
}

Switch (nodes-base.switch)

Multi-way routing - 18% of workflows

Basic Switch

Minimal:

{
  "mode": "rules",
  "rules": {
    "rules": [
      {
        "conditions": {
          "string": [
            {
              "value1": "={{$json.status}}",
              "operation": "equals",
              "value2": "active"
            }
          ]
        }
      },
      {
        "conditions": {
          "string": [
            {
              "value1": "={{$json.status}}",
              "operation": "equals",
              "value2": "pending"
            }
          ]
        }
      }
    ]
  },
  "fallbackOutput": "extra"  // Catch-all for non-matching
}

Gotcha: Number of rules must match number of outputs!


AI Nodes

OpenAI (nodes-langchain.openAi)

AI operations - 234 templates

Chat Completion

Minimal:

{
  "resource": "chat",
  "operation": "complete",
  "messages": {
    "values": [
      {
        "role": "user",
        "content": "={{$json.prompt}}"
      }
    ]
  }
}

With system prompt:

{
  "resource": "chat",
  "operation": "complete",
  "messages": {
    "values": [
      {
        "role": "system",
        "content": "You are a helpful assistant specialized in customer support."
      },
      {
        "role": "user",
        "content": "={{$json.userMessage}}"
      }
    ]
  },
  "options": {
    "temperature": 0.7,
    "maxTokens": 500
  }
}

Schedule Nodes

Schedule Trigger (nodes-base.scheduleTrigger)

Time-based workflows - 28% have schedule triggers

Daily at Specific Time

Minimal:

{
  "rule": {
    "interval": [
      {
        "field": "hours",
        "hoursInterval": 24
      }
    ],
    "hour": 9,
    "minute": 0,
    "timezone": "America/New_York"
  }
}

Gotcha: Always set timezone explicitly!

// ❌ Bad - uses server timezone
{
  "rule": {
    "interval": [...]
  }
}

// ✅ Good - explicit timezone
{
  "rule": {
    "interval": [...],
    "timezone": "America/New_York"
  }
}

Every N Minutes

Minimal:

{
  "rule": {
    "interval": [
      {
        "field": "minutes",
        "minutesInterval": 15
      }
    ]
  }
}

Cron Expression

Advanced scheduling:

{
  "mode": "cron",
  "cronExpression": "0 */2 * * *",  // Every 2 hours
  "timezone": "America/New_York"
}

Summary

Key Patterns by Category:

Category Most Common Key Gotcha
HTTP/API GET, POST JSON Remember sendBody: true
Webhooks POST receiver Data under $json.body
Communication Slack post Channel format (#name)
Database SELECT with params Use parameterized queries
Transform Set assignments Correct type per field
Conditional IF string equals Unary vs binary operators
AI OpenAI chat System + user messages
Schedule Daily at time Set timezone explicitly

Configuration Approach:

  1. Use patterns as starting point
  2. Adapt to your use case
  3. Validate configuration
  4. Iterate based on errors
  5. Deploy when valid

Related Files: