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.
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.
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
# 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
Consider JavaScript first - Use Python only when necessary
: , , or
Access data
_input.all()
_input.first()
_input.item
CRITICAL: Must return [{"json": {...}}] format
CRITICAL: Webhook data is under _json["body"] (not _json directly)
CRITICAL LIMITATION: No external libraries (no requests, pandas, numpy)
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)
# 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 else0
}
}]
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 (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
# 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
# Get first item only
first_item = _input.first()
data = first_item["json"]
return [{
"json": {
"result": process_data(data),
"processed_at": datetime.now().isoformat()
}
}]
MOST COMMON MISTAKE: Webhook data is nested under ["body"]
# ❌ 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.
# ❌ WRONG: Trying to import external libraryimport 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
# ❌ 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
# ❌ WRONG: Returning dict instead of listreturn {"json": {"result": "success"}}
# ✅ CORRECT: List wrapper requiredreturn [{"json": {"result": "success"}}]
#4: KeyError on Dictionary Access
# ❌ 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
# ❌ 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")
# ✅ 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
# ✅ GOOD: Default to 0 if None
amount = item["json"].get("amount") or0# ✅ GOOD: Check for None explicitly
text = item["json"].get("text")
if text isNone:
text = ""
3. Use List Comprehensions for Filtering
# ✅ 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
# ✅ CONSISTENT: Always list with "json" keyreturn [{"json": result}] # Single resultreturn results # Multiple results (already formatted)return [] # No results
5. Debug with print() Statements
# 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 - Comprehensive Python data access patterns
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.