# N8n Workflows

> Build n8n workflow automations - nodes, expressions, JavaScript code, and integration patterns. Use when creating or debugging n8n workflows.

- Skill: `allanninal/n8n-workflows` (Agent Skill)
- Install (CLI): `npx skillmds@latest add allanninal/n8n-workflows`
- Raw SKILL.md: https://api.skillmd.com/api/skills/allanninal/n8n-workflows/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: allanninal (https://skillmd.com/u/allanninal)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/allanninal/n8n-workflows

---


# n8n Workflow Automation

## When to Use This Skill

- Building n8n workflows
- Writing n8n expressions
- Creating Code nodes (JavaScript/Python)
- Debugging workflow errors
- Integrating n8n with external services

## n8n Basics

### Workflow Structure

```
Trigger Node → Processing Nodes → Output Nodes
     ↓              ↓                  ↓
  Webhook      Transform Data     Send Email
  Schedule     HTTP Request       Slack Message
  Manual       Code Node          Database Write
```

### Node Types

| Type | Examples | Purpose |
|------|----------|---------|
| Trigger | Webhook, Schedule, Manual | Start workflow |
| Action | HTTP Request, Email, Slack | Do something |
| Transform | Set, Function, Split | Modify data |
| Flow | If, Switch, Merge | Control logic |
| Data | Postgres, MongoDB, Redis | Data operations |

## Expressions

### Basic Syntax

```javascript
// Access input data
{{ $json.fieldName }}

// Access specific item
{{ $('Node Name').item.json.field }}

// Access all items from a node
{{ $('Node Name').all() }}

// First/last item
{{ $('Node Name').first().json.field }}
{{ $('Node Name').last().json.field }}

// Current item index
{{ $itemIndex }}

// Workflow variables
{{ $vars.myVariable }}
```

### Common Patterns

```javascript
// Conditional value
{{ $json.status === 'active' ? 'Yes' : 'No' }}

// Default value
{{ $json.name ?? 'Unknown' }}
{{ $json.name || 'Unknown' }}

// String manipulation
{{ $json.email.toLowerCase() }}
{{ $json.name.split(' ')[0] }}

// Date formatting
{{ $now.format('YYYY-MM-DD') }}
{{ $json.date.toFormat('dd/MM/yyyy') }}

// Array operations
{{ $json.items.length }}
{{ $json.items.map(i => i.name).join(', ') }}
{{ $json.items.filter(i => i.active) }}
```

### Built-in Variables

```javascript
// Current timestamp
{{ $now }}
{{ $today }}

// Workflow info
{{ $workflow.id }}
{{ $workflow.name }}

// Execution info
{{ $execution.id }}
{{ $execution.mode }}

// Environment
{{ $env.API_KEY }}
```

## Code Node (JavaScript)

### Basic Structure

```javascript
// Process each item
for (const item of $input.all()) {
  // Access data
  const name = item.json.name;
  const email = item.json.email;

  // Modify data
  item.json.processed = true;
  item.json.fullName = `${item.json.firstName} ${item.json.lastName}`;
}

return $input.all();
```

### Return New Items

```javascript
const newItems = [];

for (const item of $input.all()) {
  // Create new item structure
  newItems.push({
    json: {
      id: item.json.id,
      name: item.json.name.toUpperCase(),
      timestamp: new Date().toISOString(),
    },
  });
}

return newItems;
```

### HTTP Requests in Code

```javascript
const response = await fetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${$env.API_KEY}`,
  },
  body: JSON.stringify({
    query: $json.query,
  }),
});

const data = await response.json();

return [{ json: data }];
```

### Error Handling

```javascript
try {
  const result = await riskyOperation();
  return [{ json: { success: true, data: result } }];
} catch (error) {
  // Option 1: Return error as data
  return [{ json: { success: false, error: error.message } }];

  // Option 2: Throw to stop workflow
  throw new Error(`Operation failed: ${error.message}`);
}
```

### Async Operations

```javascript
// Multiple parallel requests
const promises = $input.all().map(async (item) => {
  const response = await fetch(`https://api.example.com/users/${item.json.id}`);
  const user = await response.json();
  return { json: { ...item.json, user } };
});

return await Promise.all(promises);
```

## Code Node (Python)

### Basic Structure

```python
# Access input items
items = _input.all()
new_items = []

for item in items:
    data = item.json

    # Process data
    result = {
        "name": data.get("name", "").upper(),
        "processed_at": datetime.now().isoformat(),
    }

    new_items.append({"json": result})

return new_items
```

### Limitations

```python
# Available modules:
# - datetime, json, math, os (limited)
# - No external package imports
# - No file system access
# - No subprocess

# For HTTP requests, use HTTP Request node instead
```

## Common Workflow Patterns

### Webhook → Process → Response

```
Webhook Trigger
     ↓
  Set Node (transform data)
     ↓
  HTTP Request (call API)
     ↓
  Respond to Webhook
```

### Scheduled Data Sync

```
Schedule Trigger (every hour)
     ↓
  HTTP Request (fetch source data)
     ↓
  Split In Batches
     ↓
  Postgres (upsert records)
     ↓
  Slack (notify completion)
```

### Error Handling Pattern

```
Main Flow
     ↓
  Try/Catch
     ├─ Success → Continue
     └─ Error → Error Handler
                    ↓
                Slack Alert
                    ↓
                Log to Database
```

### Conditional Processing

```
HTTP Request
     ↓
  IF (status check)
     ├─ True → Process A
     │            ↓
     │         Send Email
     └─ False → Process B
                   ↓
               Log Warning
```

## Debugging

### View Execution Data

```javascript
// Log to execution output
console.log('Debug:', JSON.stringify($json, null, 2));

// In expressions, check intermediate values
{{ JSON.stringify($json) }}
```

### Common Errors

```markdown
## "Cannot read property 'X' of undefined"
- Check if previous node output exists
- Use optional chaining: $json.data?.items

## "Items do not match"
- Ensure consistent item count between branches
- Use Merge node to combine items

## Expression evaluation failed
- Check syntax (missing braces, quotes)
- Verify node names match exactly
- Use $('Node Name') not $('node name')
```

### Test Workflow

```bash
# Pin data for testing
# 1. Execute workflow once
# 2. Click "Pin Data" on node output
# 3. Modify and test without re-triggering
```

## Best Practices

### Naming Conventions

```markdown
- Descriptive node names: "Fetch User Data" not "HTTP Request"
- Use prefixes for flow: "IF: Check Status", "Merge: Combine Results"
- Version your workflows: "Email Processor v2"
```

### Error Handling

```markdown
- Always add error handling for external requests
- Use "On Error" settings on critical nodes
- Set up alerting for workflow failures
- Log errors to persistent storage
```

### Performance

```markdown
- Use "Split In Batches" for large datasets
- Avoid nested loops in Code nodes
- Cache external data when possible
- Use pagination for API requests
```

### Security

```markdown
- Store secrets in credentials, not expressions
- Use environment variables for config
- Validate webhook payloads
- Limit webhook exposure (authentication)
```

## Credentials

```javascript
// Access credentials in Code node
const apiKey = $credentials.myApi.apiKey;

// In expressions
{{ $credentials.myApi.apiKey }}

// Best practice: Use HTTP Request node
// with built-in credential support
```

## Checklist

- [ ] Use descriptive node names
- [ ] Add error handling for external calls
- [ ] Test with edge cases (empty data, errors)
- [ ] Use Split In Batches for large datasets
- [ ] Store secrets in credentials
- [ ] Add notes explaining complex logic
- [ ] Set up failure notifications
- [ ] Version control workflow exports

