🎯

n8n-code-python

🎯Skill

from ovachiever/droid-tings

VibeIndex|
What it does

Enables writing Python code in n8n Code nodes using standard library functions with specific input/output syntax and node limitations.

πŸ“¦

Part of

ovachiever/droid-tings(370 items)

n8n-code-python

Installation

git cloneClone repository
git clone https://github.com/ovachiever/droid-tings.git
πŸ“– Extracted from docs: ovachiever/droid-tings
15Installs
20
-
AddedFeb 4, 2026

Skill Details

SKILL.md

Write Python code in n8n Code nodes. Use when writing Python in n8n, using _input/_json/_node syntax, working with standard library, or need to understand Python limitations in n8n Code nodes.

Overview

# Python Code Node (Beta)

Expert guidance for writing Python code in n8n Code nodes.

---

⚠️ Important: JavaScript First

Recommendation: Use JavaScript for 95% of use cases. Only use Python when:

  • You need specific Python standard library functions
  • You're significantly more comfortable with Python syntax
  • You're doing data transformations better suited to Python

Why JavaScript is preferred:

  • Full n8n helper functions ($helpers.httpRequest, etc.)
  • Luxon DateTime library for advanced date/time operations
  • No external library limitations
  • Better n8n documentation and community support

---

Quick Start

```python

# Basic template for Python Code nodes

items = _input.all()

# Process data

processed = []

for item in items:

processed.append({

"json": {

**item["json"],

"processed": True,

"timestamp": datetime.now().isoformat()

}

})

return processed

```

Essential Rules

  1. Consider JavaScript first - Use Python only when necessary
  2. Access data: _input.all(), _input.first(), or _input.item
  3. CRITICAL: Must return [{"json": {...}}] format
  4. CRITICAL: Webhook data is under _json["body"] (not _json directly)
  5. CRITICAL LIMITATION: No external libraries (no requests, pandas, numpy)
  6. Standard library only: json, datetime, re, base64, hashlib, urllib.parse, math, random, statistics

---

Mode Selection Guide

Same as JavaScript - choose based on your use case:

Run Once for All Items (Recommended - Default)

Use this mode for: 95% of use cases

  • How it works: Code executes once regardless of input count
  • Data access: _input.all() or _items array (Native mode)
  • Best for: Aggregation, filtering, batch processing, transformations
  • Performance: Faster for multiple items (single execution)

```python

# Example: Calculate total from all items

all_items = _input.all()

total = sum(item["json"].get("amount", 0) for item in all_items)

return [{

"json": {

"total": total,

"count": len(all_items),

"average": total / len(all_items) if all_items else 0

}

}]

```

Run Once for Each Item

Use this mode for: Specialized cases only

  • How it works: Code executes separately for each input item
  • Data access: _input.item or _item (Native mode)
  • Best for: Item-specific logic, independent operations, per-item validation
  • Performance: Slower for large datasets (multiple executions)

```python

# Example: Add processing timestamp to each item

item = _input.item

return [{

"json": {

**item["json"],

"processed": True,

"processed_at": datetime.now().isoformat()

}

}]

```

---

Python Modes: Beta vs Native

n8n offers two Python execution modes:

Python (Beta) - Recommended

  • Use: _input, _json, _node helper syntax
  • Best for: Most Python use cases
  • Helpers available: _now, _today, _jmespath()
  • Import: from datetime import datetime

```python

# Python (Beta) example

items = _input.all()

now = _now # Built-in datetime object

return [{

"json": {

"count": len(items),

"timestamp": now.isoformat()

}

}]

```

Python (Native) (Beta)

  • Use: _items, _item variables only
  • No helpers: No _input, _now, etc.
  • More limited: Standard Python only
  • Use when: Need pure Python without n8n helpers

```python

# Python (Native) example

processed = []

for item in _items:

processed.append({

"json": {

"id": item["json"].get("id"),

"processed": True

}

})

return processed

```

Recommendation: Use Python (Beta) for better n8n integration.

---

Data Access Patterns

Pattern 1: _input.all() - Most Common

Use when: Processing arrays, batch operations, aggregations

```python

# Get all items from previous node

all_items = _input.all()

# Filter, transform as needed

valid = [item for item in all_items if item["json"].get("status") == "active"]

processed = []

for item in valid:

processed.append({

"json": {

"id": item["json"]["id"],

"name": item["json"]["name"]

}

})

return processed

```

Pattern 2: _input.first() - Very Common

Use when: Working with single objects, API responses

```python

# Get first item only

first_item = _input.first()

data = first_item["json"]

return [{

"json": {

"result": process_data(data),

"processed_at": datetime.now().isoformat()

}

}]

```

Pattern 3: _input.item - Each Item Mode Only

Use when: In "Run Once for Each Item" mode

```python

# Current item in loop (Each Item mode only)

current_item = _input.item

return [{

"json": {

**current_item["json"],

"item_processed": True

}

}]

```

Pattern 4: _node - Reference Other Nodes

Use when: Need data from specific nodes in workflow

```python

# Get output from specific node

webhook_data = _node["Webhook"]["json"]

http_data = _node["HTTP Request"]["json"]

return [{

"json": {

"combined": {

"webhook": webhook_data,

"api": http_data

}

}

}]

```

See: [DATA_ACCESS.md](DATA_ACCESS.md) for comprehensive guide

---

Critical: Webhook Data Structure

MOST COMMON MISTAKE: Webhook data is nested under ["body"]

```python

# ❌ WRONG - Will raise KeyError

name = _json["name"]

email = _json["email"]

# βœ… CORRECT - Webhook data is under ["body"]

name = _json["body"]["name"]

email = _json["body"]["email"]

# βœ… SAFER - Use .get() for safe access

webhook_data = _json.get("body", {})

name = webhook_data.get("name")

```

Why: Webhook node wraps all request data under body property. This includes POST data, query parameters, and JSON payloads.

See: [DATA_ACCESS.md](DATA_ACCESS.md) for full webhook structure details

---

Return Format Requirements

CRITICAL RULE: Always return list of dictionaries with "json" key

Correct Return Formats

```python

# βœ… Single result

return [{

"json": {

"field1": value1,

"field2": value2

}

}]

# βœ… Multiple results

return [

{"json": {"id": 1, "data": "first"}},

{"json": {"id": 2, "data": "second"}}

]

# βœ… List comprehension

transformed = [

{"json": {"id": item["json"]["id"], "processed": True}}

for item in _input.all()

if item["json"].get("valid")

]

return transformed

# βœ… Empty result (when no data to return)

return []

# βœ… Conditional return

if should_process:

return [{"json": processed_data}]

else:

return []

```

Incorrect Return Formats

```python

# ❌ WRONG: Dictionary without list wrapper

return {

"json": {"field": value}

}

# ❌ WRONG: List without json wrapper

return [{"field": value}]

# ❌ WRONG: Plain string

return "processed"

# ❌ WRONG: Incomplete structure

return [{"data": value}] # Should be {"json": value}

```

Why it matters: Next nodes expect list format. Incorrect format causes workflow execution to fail.

See: [ERROR_PATTERNS.md](ERROR_PATTERNS.md) #2 for detailed error solutions

---

Critical Limitation: No External Libraries

MOST IMPORTANT PYTHON LIMITATION: Cannot import external packages

What's NOT Available

```python

# ❌ NOT AVAILABLE - Will raise ModuleNotFoundError

import requests # ❌ No

import pandas # ❌ No

import numpy # ❌ No

import scipy # ❌ No

from bs4 import BeautifulSoup # ❌ No

import lxml # ❌ No

```

What IS Available (Standard Library)

```python

# βœ… AVAILABLE - Standard library only

import json # βœ… JSON parsing

import datetime # βœ… Date/time operations

import re # βœ… Regular expressions

import base64 # βœ… Base64 encoding/decoding

import hashlib # βœ… Hashing functions

import urllib.parse # βœ… URL parsing

import math # βœ… Math functions

import random # βœ… Random numbers

import statistics # βœ… Statistical functions

```

Workarounds

Need HTTP requests?

  • βœ… Use HTTP Request node before Code node
  • βœ… Or switch to JavaScript and use $helpers.httpRequest()

Need data analysis (pandas/numpy)?

  • βœ… Use Python statistics module for basic stats
  • βœ… Or switch to JavaScript for most operations
  • βœ… Manual calculations with lists and dictionaries

Need web scraping (BeautifulSoup)?

  • βœ… Use HTTP Request node + HTML Extract node
  • βœ… Or switch to JavaScript with regex/string methods

See: [STANDARD_LIBRARY.md](STANDARD_LIBRARY.md) for complete reference

---

Common Patterns Overview

Based on production workflows, here are the most useful Python patterns:

1. Data Transformation

Transform all items with list comprehensions

```python

items = _input.all()

return [

{

"json": {

"id": item["json"].get("id"),

"name": item["json"].get("name", "Unknown").upper(),

"processed": True

}

}

for item in items

]

```

2. Filtering & Aggregation

Sum, filter, count with built-in functions

```python

items = _input.all()

total = sum(item["json"].get("amount", 0) for item in items)

valid_items = [item for item in items if item["json"].get("amount", 0) > 0]

return [{

"json": {

"total": total,

"count": len(valid_items)

}

}]

```

3. String Processing with Regex

Extract patterns from text

```python

import re

items = _input.all()

email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'

all_emails = []

for item in items:

text = item["json"].get("text", "")

emails = re.findall(email_pattern, text)

all_emails.extend(emails)

# Remove duplicates

unique_emails = list(set(all_emails))

return [{

"json": {

"emails": unique_emails,

"count": len(unique_emails)

}

}]

```

4. Data Validation

Validate and clean data

```python

items = _input.all()

validated = []

for item in items:

data = item["json"]

errors = []

# Validate fields

if not data.get("email"):

errors.append("Email required")

if not data.get("name"):

errors.append("Name required")

validated.append({

"json": {

**data,

"valid": len(errors) == 0,

"errors": errors if errors else None

}

})

return validated

```

5. Statistical Analysis

Calculate statistics with statistics module

```python

from statistics import mean, median, stdev

items = _input.all()

values = [item["json"].get("value", 0) for item in items if "value" in item["json"]]

if values:

return [{

"json": {

"mean": mean(values),

"median": median(values),

"stdev": stdev(values) if len(values) > 1 else 0,

"min": min(values),

"max": max(values),

"count": len(values)

}

}]

else:

return [{"json": {"error": "No values found"}}]

```

See: [COMMON_PATTERNS.md](COMMON_PATTERNS.md) for 10 detailed Python patterns

---

Error Prevention - Top 5 Mistakes

#1: Importing External Libraries (Python-Specific!)

```python

# ❌ WRONG: Trying to import external library

import requests # ModuleNotFoundError!

# βœ… CORRECT: Use HTTP Request node or JavaScript

# Add HTTP Request node before Code node

# OR switch to JavaScript and use $helpers.httpRequest()

```

#2: Empty Code or Missing Return

```python

# ❌ WRONG: No return statement

items = _input.all()

# Processing...

# Forgot to return!

# βœ… CORRECT: Always return data

items = _input.all()

# Processing...

return [{"json": item["json"]} for item in items]

```

#3: Incorrect Return Format

```python

# ❌ WRONG: Returning dict instead of list

return {"json": {"result": "success"}}

# βœ… CORRECT: List wrapper required

return [{"json": {"result": "success"}}]

```

#4: KeyError on Dictionary Access

```python

# ❌ WRONG: Direct access crashes if missing

name = _json["user"]["name"] # KeyError!

# βœ… CORRECT: Use .get() for safe access

name = _json.get("user", {}).get("name", "Unknown")

```

#5: Webhook Body Nesting

```python

# ❌ WRONG: Direct access to webhook data

email = _json["email"] # KeyError!

# βœ… CORRECT: Webhook data under ["body"]

email = _json["body"]["email"]

# βœ… BETTER: Safe access with .get()

email = _json.get("body", {}).get("email", "no-email")

```

See: [ERROR_PATTERNS.md](ERROR_PATTERNS.md) for comprehensive error guide

---

Standard Library Reference

Most Useful Modules

```python

# JSON operations

import json

data = json.loads(json_string)

json_output = json.dumps({"key": "value"})

# Date/time

from datetime import datetime, timedelta

now = datetime.now()

tomorrow = now + timedelta(days=1)

formatted = now.strftime("%Y-%m-%d")

# Regular expressions

import re

matches = re.findall(r'\d+', text)

cleaned = re.sub(r'[^\w\s]', '', text)

# Base64 encoding

import base64

encoded = base64.b64encode(data).decode()

decoded = base64.b64decode(encoded)

# Hashing

import hashlib

hash_value = hashlib.sha256(text.encode()).hexdigest()

# URL parsing

import urllib.parse

params = urllib.parse.urlencode({"key": "value"})

parsed = urllib.parse.urlparse(url)

# Statistics

from statistics import mean, median, stdev

average = mean([1, 2, 3, 4, 5])

```

See: [STANDARD_LIBRARY.md](STANDARD_LIBRARY.md) for complete reference

---

Best Practices

1. Always Use .get() for Dictionary Access

```python

# βœ… SAFE: Won't crash if field missing

value = item["json"].get("field", "default")

# ❌ RISKY: Crashes if field doesn't exist

value = item["json"]["field"]

```

2. Handle None/Null Values Explicitly

```python

# βœ… GOOD: Default to 0 if None

amount = item["json"].get("amount") or 0

# βœ… GOOD: Check for None explicitly

text = item["json"].get("text")

if text is None:

text = ""

```

3. Use List Comprehensions for Filtering

```python

# βœ… PYTHONIC: List comprehension

valid = [item for item in items if item["json"].get("active")]

# ❌ VERBOSE: Manual loop

valid = []

for item in items:

if item["json"].get("active"):

valid.append(item)

```

4. Return Consistent Structure

```python

# βœ… CONSISTENT: Always list with "json" key

return [{"json": result}] # Single result

return results # Multiple results (already formatted)

return [] # No results

```

5. Debug with print() Statements

```python

# Debug statements appear in browser console (F12)

items = _input.all()

print(f"Processing {len(items)} items")

print(f"First item: {items[0] if items else 'None'}")

```

---

When to Use Python vs JavaScript

Use Python When:

  • βœ… You need statistics module for statistical operations
  • βœ… You're significantly more comfortable with Python syntax
  • βœ… Your logic maps well to list comprehensions
  • βœ… You need specific standard library functions

Use JavaScript When:

  • βœ… You need HTTP requests ($helpers.httpRequest())
  • βœ… You need advanced date/time (DateTime/Luxon)
  • βœ… You want better n8n integration
  • βœ… For 95% of use cases (recommended)

Consider Other Nodes When:

  • ❌ Simple field mapping β†’ Use Set node
  • ❌ Basic filtering β†’ Use Filter node
  • ❌ Simple conditionals β†’ Use IF or Switch node
  • ❌ HTTP requests only β†’ Use HTTP Request node

---

Integration with Other Skills

Works With:

n8n Expression Syntax:

  • Expressions use {{ }} syntax in other nodes
  • Code nodes use Python directly (no {{ }})
  • When to use expressions vs code

n8n MCP Tools Expert:

  • How to find Code node: search_nodes({query: "code"})
  • Get configuration help: get_node_essentials("nodes-base.code")
  • Validate code: validate_node_operation()

n8n Node Configuration:

  • Mode selection (All Items vs Each Item)
  • Language selection (Python vs JavaScript)
  • Understanding property dependencies

n8n Workflow Patterns:

  • Code nodes in transformation step
  • When to use Python vs JavaScript in patterns

n8n Validation Expert:

  • Validate Code node configuration
  • Handle validation errors
  • Auto-fix common issues

n8n Code JavaScript:

  • When to use JavaScript instead
  • Comparison of JavaScript vs Python features
  • Migration from Python to JavaScript

---

Quick Reference Checklist

Before deploying Python Code nodes, verify:

  • [ ] Considered JavaScript first - Using Python only when necessary
  • [ ] Code is not empty - Must have meaningful logic
  • [ ] Return statement exists - Must return list of dictionaries
  • [ ] Proper return format - Each item: {"json": {...}}
  • [ ] Data access correct - Using _input.all(), _input.first(), or _input.item
  • [ ] No external imports - Only standard library (json, datetime, re, etc.)
  • [ ] Safe dictionary access - Using .get() to avoid KeyError
  • [ ] Webhook data - Access via ["body"] if from webhook
  • [ ] Mode selection - "All Items" for most cases
  • [ ] Output consistent - All code paths return same structure

---

Additional Resources

Related Files

  • [DATA_ACCESS.md](DATA_ACCESS.md) - Comprehensive Python data access patterns
  • [COMMON_PATTERNS.md](COMMON_PATTERNS.md) - 10 Python patterns for n8n
  • [ERROR_PATTERNS.md](ERROR_PATTERNS.md) - Top 5 errors and solutions
  • [STANDARD_LIBRARY.md](STANDARD_LIBRARY.md) - Complete standard library reference

n8n Documentation

  • Code Node Guide: https://docs.n8n.io/code/code-node/
  • Python in n8n: https://docs.n8n.io/code/builtin/python-modules/

---

Ready to write Python in n8n Code nodes - but consider JavaScript first! Use Python for specific needs, reference the error patterns guide to avoid common mistakes, and leverage the standard library effectively.