🏠 Home / Hub

n8n 03 — Data & Expressions

Understanding how data flows through n8n and how to transform it with expressions and code is the key skill that separates basic automations from powerful ones.

1. n8n Data Model

Data in n8n flows as an array of items. Each item has two parts:

// A typical item structure
{
  json: {
    id: 42,
    name: "Alice",
    email: "alice@example.com",
    score: 95
  },
  binary: {
    // optional: file attachments, images, etc.
    data: { mimeType: "image/png", data: "base64string..." }
  }
}

When an HTTP Request returns an array of 10 users, n8n creates 10 items — one per user. Most nodes process each item individually in a loop.

Think of items like rows in a spreadsheet. Each node transforms, filters, or enriches the rows before passing them to the next node.

2. Expression Syntax

Expressions use double curly braces {{ }} and give you access to dynamic data. Click the lightning bolt icon next to any field to switch from a static value to an expression.

# Access current item fields
{{ $json.name }}
{{ $json.user.email }}
{{ $json["field-with-dashes"] }}

# Access a specific node's output
{{ $node["HTTP Request"].json.id }}
{{ $('Fetch Users').item.json.email }}

# Access item by position
{{ $('Fetch Users').first().json.name }}
{{ $('Fetch Users').last().json.name }}

3. Accessing Previous Node Data

# Modern syntax (n8n v1+)
{{ $('NodeName').item.json.field }}
{{ $('NodeName').all()[0].json.field }}

# Legacy syntax (still works)
{{ $node["NodeName"].json.field }}

# Example: get the ID from step 2 while in step 4
{{ $('Fetch Product').item.json.product_id }}

# Access response from HTTP Request node
{{ $('Call API').item.json.data.users[0].name }}
Node names are case-sensitive. Rename nodes descriptively (e.g. "Fetch Users" not "HTTP Request1") so expressions stay readable.

4. Built-in Variables

VariableDescriptionExample output
$jsonCurrent item's JSON data{ name: "Alice" }
$nowCurrent datetime (Luxon object)2024-06-15T09:30:00.000Z
$todayToday's date at midnight2024-06-15T00:00:00.000Z
$runIndexWhich run of the workflow (0-based)0
$itemIndexIndex of current item in the batch3
$workflow.idCurrent workflow's ID"abc123"
$execution.idCurrent execution's ID"exec_xyz"

5. Date Manipulation

n8n uses Luxon for date handling. $now and $today are Luxon DateTime objects.

# Format dates
{{ $now.toISO() }}                      # "2024-06-15T09:30:00.000Z"
{{ $now.toFormat('yyyy-MM-dd') }}       # "2024-06-15"
{{ $now.toFormat('dd/MM/yyyy HH:mm') }} # "15/06/2024 09:30"

# Date arithmetic
{{ $now.minus({ days: 7 }).toISO() }}   # 7 days ago
{{ $now.plus({ hours: 2 }).toISO() }}   # 2 hours from now
{{ $now.startOf('month').toISO() }}     # First day of month
{{ $now.endOf('week').toISO() }}        # End of current week

# Parse an existing date string
{{ DateTime.fromISO($json.created_at).toFormat('MMM d, yyyy') }}
{{ DateTime.fromFormat($json.date, 'dd/MM/yyyy').toISO() }}

6. String Operations in Expressions

# Standard JavaScript string methods
{{ $json.name.toUpperCase() }}           # "ALICE"
{{ $json.name.toLowerCase() }}           # "alice"
{{ $json.email.split('@')[1] }}          # "example.com"
{{ $json.title.includes('urgent') }}     # true/false
{{ $json.message.replace('foo','bar') }} # replace text
{{ $json.name.trim() }}                  # strip whitespace
{{ $json.code.padStart(6,'0') }}         # "000042"

# Template literals
{{ `Hello ${$json.name}, score: ${$json.score}` }}

# Conditional (ternary)
{{ $json.score >= 70 ? 'Pass' : 'Fail' }}

7. Code Node — Full JavaScript

When expressions aren't enough, the Code node gives you a full JavaScript environment. Access all input items via $input.all() and return a new array of items.

// Code node — Run Once for All Items mode
const items = $input.all();

const result = items.map(item => {
  const data = item.json;
  return {
    json: {
      fullName: `${data.firstName} ${data.lastName}`,
      emailDomain: data.email.split('@')[1],
      isHighValue: data.orderTotal > 1000,
      processedAt: new Date().toISOString()
    }
  };
});

return result;
Always return an array of objects with a json key. Forgetting this is the most common Code node mistake.

8. Filtering & Transforming with Code Node

// Filter: only keep items where score > 70
const items = $input.all();
return items
  .filter(item => item.json.score > 70)
  .map(item => ({ json: item.json }));

// Group items by category
const grouped = {};
$input.all().forEach(item => {
  const cat = item.json.category;
  if (!grouped[cat]) grouped[cat] = [];
  grouped[cat].push(item.json);
});
return Object.entries(grouped).map(([cat, rows]) => ({
  json: { category: cat, count: rows.length, items: rows }
}));

// Flatten a nested array from an API response
const raw = $input.first().json.data.users;
return raw.map(user => ({ json: user }));

9. Common Expression Patterns

TaskExpression
Current timestamp (ISO){{ $now.toISO() }}
Item field{{ $json.fieldName }}
Nested field{{ $json.user.address.city }}
Array element{{ $json.tags[0] }}
Conditional value{{ $json.active ? 'Yes' : 'No' }}
From another node{{ $('Step2').item.json.id }}
String interpolation{{ `Order #${$json.id}` }}
Math operation{{ $json.price * $json.qty }}
Null default{{ $json.name ?? 'Unknown' }}
7 days ago{{ $now.minus({days:7}).toISO() }}

📌 Study Checklist