---
name: n8n-expression-syntax
description: "สกิลสำหรับ N8n Expression Syntax ใช้เมื่อต้องการแนวทาง ขั้นตอน Template หรือคำแนะนำเชิงปฏิบัติสำหรับงาน DevOps, Cloud, Infrastructure, Automation, Deployment และ Monitoring ในหัวข้อนี้"
---

# N8n Expression Syntax

Expert guide for writing correct n8n expressions in workflows.

---

## Expression Format

All dynamic content in n8n uses **double curly braces**:

```
{{expression}}
```

**Examples**:
```
✅ {{$JSON.email}}
✅ {{$JSON.body.name}}
✅ {{$node["HTTP Request"].JSON.data}}
❌ $JSON.email  (no braces - treated as literal text)
❌ {$JSON.email}  (single braces - invalid)
```

---

## Core Variables

### $JSON - Current Node Output

Access data from the current node:

```javascript
{{$JSON.fieldName}}
{{$JSON['field with spaces']}}
{{$JSON.nested.property}}
{{$JSON.items[0].name}}
```

### $node - Reference Other Nodes

Access data from any previous node:

```javascript
{{$node["Node Name"].JSON.fieldName}}
{{$node["HTTP Request"].JSON.data}}
{{$node["Webhook"].JSON.body.email}}
```

**Important**:
- Node names **must** be in quotes
- Node names are **case-sensitive**
- Must match exact node name from workflow

### $now - Current Timestamp

Access current date/time:

```javascript
{{$now}}
{{$now.toFormat('yyyy-MM-dd')}}
{{$now.toFormat('HH:mm:ss')}}
{{$now.plus({days: 7})}}
```

### $env - Environment Variables

Access environment variables:

```javascript
{{$env.API_KEY}}
{{$env.DATABASE_URL}}
```

---

## 🚨 CRITICAL: Webhook Data Structure

**Most Common Mistake**: Webhook data is **NOT** at the root!

### Webhook Node Output Structure

```javascript
{
  "headers": {...},
  "params": {...},
  "query": {...},
  "body": {           // ⚠️ USER DATA IS HERE!
    "name": "John",
    "email": "john@example.com",
    "message": "Hello"
  }
}
```

### Correct Webhook Data Access

```javascript
❌ WRONG: {{$JSON.name}}
❌ WRONG: {{$JSON.email}}

✅ CORRECT: {{$JSON.body.name}}
✅ CORRECT: {{$JSON.body.email}}
✅ CORRECT: {{$JSON.body.message}}
```

**Why**: Webhook node wraps incoming data under `.body` property to preserve headers, params, and query parameters.

---

## Common Patterns

### Access Nested Fields

```javascript
// Simple nesting
{{$JSON.user.email}}

// Array access
{{$JSON.data[0].name}}
{{$JSON.items[0].id}}

// Bracket notation for spaces
{{$JSON['field name']}}
{{$JSON['user data']['first name']}}
```

### Reference Other Nodes

```javascript
// Node without spaces
{{$node["Set"].JSON.value}}

// Node with spaces (common!)
{{$node["HTTP Request"].JSON.data}}
{{$node["Respond to Webhook"].JSON.message}}

// Webhook node
{{$node["Webhook"].JSON.body.email}}
```

### Combine Variables

```javascript
// Concatenation (automatic)
Hello {{$JSON.body.name}}!

// In URLs
https://API.example.com/users/{{$JSON.body.user_id}}

// In object properties
{
  "name": "={{$JSON.body.name}}",
  "email": "={{$JSON.body.email}}"
}
```

---

## When NOT to Use Expressions

### ❌ Code Nodes

Code nodes use **direct JavaScript access**, NOT expressions!

```javascript
// ❌ WRONG in Code node
const email = '={{$JSON.email}}';
const name = '{{$JSON.body.name}}';

// ✅ CORRECT in Code node
const email = $JSON.email;
const name = $JSON.body.name;

// Or using Code node API
const email = $input.item.JSON.email;
const allItems = $input.all();
```

### ❌ Webhook Paths

```javascript
// ❌ WRONG
path: "{{$JSON.user_id}}/webhook"

// ✅ CORRECT
path: "user-webhook"  // Static paths only
```

### ❌ Credential Fields

```javascript
// ❌ WRONG
apiKey: "={{$env.API_KEY}}"

// ✅ CORRECT
Use n8n credential system, not expressions
```

---

## Validation Rules

### 1. Always Use {{}}

Expressions **must** be wrapped in double curly braces.

```javascript
❌ $JSON.field
✅ {{$JSON.field}}
```

### 2. Use Quotes for Spaces

Field or node names with spaces require **bracket notation**:

```javascript
❌ {{$JSON.field name}}
✅ {{$JSON['field name']}}

❌ {{$node.HTTP Request.JSON}}
✅ {{$node["HTTP Request"].JSON}}
```

### 3. Match Exact Node Names

Node references are **case-sensitive**:

```javascript
❌ {{$node["http request"].JSON}}  // lowercase
❌ {{$node["Http Request"].JSON}}  // wrong case
✅ {{$node["HTTP Request"].JSON}}  // exact match
```

### 4. No Nested {{}}

Don't double-wrap expressions:

```javascript
❌ {{{$JSON.field}}}
✅ {{$JSON.field}}
```

---

## Common Mistakes

For complete error catalog with fixes, see [COMMON_MISTAKES.md](COMMON_MISTAKES.md)

### Quick Fixes

| Mistake | Fix |
|---------|-----|
| `$JSON.field` | `{{$JSON.field}}` |
| `{{$JSON.field name}}` | `{{$JSON['field name']}}` |
| `{{$node.HTTP Request}}` | `{{$node["HTTP Request"]}}` |
| `{{{$JSON.field}}}` | `{{$JSON.field}}` |
| `{{$JSON.name}}` (webhook) | `{{$JSON.body.name}}` |
| `'={{$JSON.email}}'` (Code node) | `$JSON.email` |

---

## Working Examples

For real workflow examples, see [EXAMPLES.md](EXAMPLES.md)

### Example 1: Webhook to Slack

**Webhook receives**:
```JSON
{
  "body": {
    "name": "John Doe",
    "email": "john@example.com",
    "message": "Hello!"
  }
}
```

**In Slack node text field**:
```
New form submission!

Name: {{$JSON.body.name}}
Email: {{$JSON.body.email}}
Message: {{$JSON.body.message}}
```

### Example 2: HTTP Request to Email

**HTTP Request returns**:
```JSON
{
  "data": {
    "items": [
      {"name": "Product 1", "price": 29.99}
    ]
  }
}
```

**In Email node** (reference HTTP Request):
```
Product: {{$node["HTTP Request"].JSON.data.items[0].name}}
Price: ${{$node["HTTP Request"].JSON.data.items[0].price}}
```

### Example 3: Format Timestamp

```javascript
// Current date
{{$now.toFormat('yyyy-MM-dd')}}
// Result: 2025-10-20

// Time
{{$now.toFormat('HH:mm:ss')}}
// Result: 14:30:45

// Full datetime
{{$now.toFormat('yyyy-MM-dd HH:mm')}}
// Result: 2025-10-20 14:30
```

---

## Data Type Handling

### Arrays

```javascript
// First item
{{$JSON.users[0].email}}

// Array length
{{$JSON.users.length}}

// Last item
{{$JSON.users[$JSON.users.length - 1].name}}
```

### Objects

```javascript
// Dot notation (no spaces)
{{$JSON.user.email}}

// Bracket notation (with spaces or dynamic)
{{$JSON['user data'].email}}
```

### Strings

```javascript
// Concatenation (automatic)
Hello {{$JSON.name}}!

// String methods
{{$JSON.email.toLowerCase()}}
{{$JSON.name.toUpperCase()}}
```

### Numbers

```javascript
// Direct use
{{$JSON.price}}

// Math operations
{{$JSON.price * 1.1}}  // Add 10%
{{$JSON.quantity + 5}}
```

---

## Advanced Patterns

### Conditional Content

```javascript
// Ternary operator
{{$JSON.status === 'active' ? 'Active User' : 'Inactive User'}}

// Default values
{{$JSON.email || 'no-email@example.com'}}
```

### Date Manipulation

```javascript
// Add days
{{$now.plus({days: 7}).toFormat('yyyy-MM-dd')}}

// Subtract hours
{{$now.minus({hours: 24}).toISO()}}

// Set specific date
{{DateTime.fromISO('2025-12-25').toFormat('MMMM dd, yyyy')}}
```

### String Manipulation

```javascript
// Substring
{{$JSON.email.substring(0, 5)}}

// Replace
{{$JSON.message.replace('old', 'new')}}

// Split and join
{{$JSON.tags.split(',').join(', ')}}
```

---

## Debugging Expressions

### Test in Expression Editor

1. Click field with expression
2. Open expression editor (click "fx" icon)
3. See live preview of result
4. Check for errors highlighted in red

### Common Error Messages

**"Cannot read property 'X' of undefined"**
→ Parent object doesn't exist
→ Check your data path

**"X is not a function"**
→ Trying to call method on non-function
→ Check variable type

**Expression shows as literal text**
→ Missing {{ }}
→ Add curly braces

---

## Expression Helpers

### Available Methods

**String**:
- `.toLowerCase()`, `.toUpperCase()`
- `.trim()`, `.replace()`, `.substring()`
- `.split()`, `.includes()`

**Array**:
- `.length`, `.map()`, `.filter()`
- `.find()`, `.join()`, `.slice()`

**DateTime** (Luxon):
- `.toFormat()`, `.toISO()`, `.toLocal()`
- `.plus()`, `.minus()`, `.set()`

**Number**:
- `.toFixed()`, `.toString()`
- Math operations: `+`, `-`, `*`, `/`, `%`

---

## Best Practices

### ✅ Do

- Always use {{ }} for dynamic content
- Use bracket notation for field names with spaces
- Reference webhook data from `.body`
- Use $node for data from other nodes
- Test expressions in expression editor

### ❌ Don't

- Don't use expressions in Code nodes
- Don't forget quotes around node names with spaces
- Don't double-wrap with extra {{ }}
- Don't assume webhook data is at root (it's under .body!)
- Don't use expressions in webhook paths or credentials

---

## Related Skills

- **n8n MCP Tools Expert**: Learn how to validate expressions using MCP tools
- **n8n Workflow Patterns**: See expressions in real workflow examples
- **n8n Node Configuration**: Understand when expressions are needed

---

## Summary

**Essential Rules**:
1. Wrap expressions in {{ }}
2. Webhook data is under `.body`
3. No {{ }} in Code nodes
4. Quote node names with spaces
5. Node names are case-sensitive

**Most Common Mistakes**:
- Missing {{ }} → Add braces
- `{{$JSON.name}}` in webhooks → Use `{{$JSON.body.name}}`
- `{{$JSON.email}}` in Code → Use `$JSON.email`
- `{{$node.HTTP Request}}` → Use `{{$node["HTTP Request"]}}`

For more details, see:
- [COMMON_MISTAKES.md](COMMON_MISTAKES.md) - Complete error catalog
- [EXAMPLES.md](EXAMPLES.md) - Real workflow examples

---

**Need Help?** Reference the n8n expression documentation or use n8n-mcp validation tools to check your expressions.
