# n8n Guidelines for AI Agents (v1.112+) ## CONTEXT DETECTION Use these guidelines when: - Working on n8n Code node (JavaScript or Python) - Working on n8n expressions in Set node or any expression field - User mentions n8n workflow automation ## DOCUMENTATION SOURCES For complete detailed documentation with examples and edge cases: - Expressions: https://cdn.n8n.community/expression.md - Code Node: https://cdn.n8n.community/code.md Fetch these when user needs in-depth explanations or complex examples. ## CODE NODE RULES (JavaScript/Python) CRITICAL: NEVER use $items() - DEPRECATED. Always use $('NodeName').all() CRITICAL: NEVER wrap main execution in functions - n8n Code Nodes are scripts not functions CRITICAL: ONLY ONE return statement allowed - Must be at end of top-level execution CRITICAL: Default to JavaScript unless explicitly asked for Python CRITICAL: Python has SEVERE limitations - avoid unless requested CRITICAL: Always return array of objects with json property: return [{json: data}] ### WRONG CODE STRUCTURE: function processData($input) { const items = $input.all(); return results; // ILLEGAL in n8n top-level } return processData($input); // CAUSES "Illegal return statement" ### CORRECT CODE STRUCTURE: const items = $input.all(); const results = []; for (const item of items) { results.push({ json: processedData }); } return results; // ONLY valid return in n8n Code Node ### DATA ACCESS PATTERNS: $input.all() - Get all input items $input.first() - Get first item $input.last() - Get last item $input.item - Only in "Run Once for Each Item" mode $('HTTP Request').all() - All items from node $('HTTP Request').first() - First item $('HTTP Request').last() - Last item $input.item.json - Current item's data $input.all().map(item => item.json) - All items' data ### REQUIRED RETURN FORMAT: return [{ json: { /* your data */ }, binary: {} }]; return [ { json: { id: 1, name: "Item1" } }, { json: { id: 2, name: "Item2" } } ]; ### AVAILABLE VARIABLES: $workflow.id - Workflow ID $workflow.name - Workflow name $execution.id - Execution ID $execution.mode - 'test' or 'production' $env.VARIABLE_NAME - Environment variables $vars.globalVar - Global variables ### HELPER METHODS: $evaluateExpression(expr, itemIndex) - Evaluate n8n expressions $ifEmpty(value, defaultValue) - Return default if empty $jmespath(data, 'query.path') - Query JSON with JMESPath ### PYTHON LIMITATIONS: DO NOT USE Python for: - HTTP requests (no network access) - File system operations (blocked) - External packages (pip not available) - OS operations (security blocked) ### TOP-LEVEL EXECUTION PATTERN: function transformData(input) { return transformed; } function main() { const items = $input.all(); const results = []; for (const item of items) { try { const transformed = transformData(item.json); results.push({ json: transformed }); } catch (error) { console.error(`Error: ${error.message}`); results.push({ json: { error: error.message } }); } } return results; } // @ts-ignore return main(); ### MINIFICATION HANDLING: PRIMARY: return main(); (requires minifier config "toplevel": false) LEGACY FALLBACK: return (() => main())(); (only if minifier cannot be changed) ### TYPESCRIPT SUPPRESSION: Use @ts-ignore for n8n globals and top-level returns // @ts-ignore const items = $input.all(); // @ts-ignore return main(); ## EXPRESSION RULES (Set Node and Expression Fields) CRITICAL: Expressions use {{ }} syntax - NEVER forget double braces CRITICAL: Must be SINGLE LINE - no line breaks allowed CRITICAL: Can chain methods but keep on one line CRITICAL: Toggle parameter to "Expression" mode first ### BASIC STRUCTURE: {{ javascript_expression_here }} ### ACCESSING DATA: {{ $json.fieldName }} - Current item's field {{ $json["field-name"] }} - Fields with special characters {{ $input.item.json.fieldName }} - Explicit current item {{ $input.all()[0].json.fieldName }} - First item's field {{ $('Node Name').item.json.fieldName }} - Specific node's current item {{ $('Node Name').first().json.field }} - First item from node {{ $('Node Name').last().json.field }} - Last item from node {{ $('Node Name').all()[0].json.field }} - Specific item by index {{ $json.user.profile.email }} - Nested data {{ $json.items[0].name }} - Array access {{ $json["special-key"]["nested-field"] }} - Special characters ### STRING TRANSFORMATIONS: {{ "email@example.com".isEmail() }} - Returns true {{ "https://example.com/path".extractDomain() }} - Returns "example.com" {{ "
Text
".removeTags() }} - Returns "Text" {{ "Hello World".toSnakeCase() }} - Returns "hello_world" {{ "hello_world".toCamelCase() }} - Returns "helloWorld" {{ "text".base64Encode() }} - Base64 encode {{ "dGV4dA==".base64Decode() }} - Base64 decode {{ "https://site.com/path?q=1".extractUrlPath() }} - Returns "/path" ### ARRAY TRANSFORMATIONS: {{ [1, 2, 2, 3].removeDuplicates() }} - Returns [1, 2, 3] {{ [10, 20, 30].sum() }} - Returns 60 {{ [1, 2].merge([3, 4]) }} - Returns [1, 2, 3, 4] {{ [].isEmpty() }} - Returns true {{ ["a", "b", "c"].randomItem() }} - Random element {{ [1, 2, 3].first() }} - Returns 1 {{ [1, 2, 3].last() }} - Returns 3 ### NUMBER TRANSFORMATIONS: {{ 123.456.round(2) }} - Returns 123.46 {{ 0.toBoolean() }} - Returns false {{ 1000.format('en-US') }} - Returns "1,000" {{ 10.isEven() }} - Returns true {{ 11.isOdd() }} - Returns true ### OBJECT TRANSFORMATIONS: {{ {}.isEmpty() }} - Returns true {{ {"a": 1, "b": 2}.removeField("b") }} - Returns {"a": 1} {{ {"a": 1}.merge({"b": 2}) }} - Returns {"a": 1, "b": 2} {{ {"key": "value"}.toJsonString() }} - JSON string ### BOOLEAN TRANSFORMATIONS: {{ true.toInt() }} - Returns 1 {{ false.toInt() }} - Returns 0 ### DATE OPERATIONS: {{ "2025-01-15".toDateTime() }} - Parse to DateTime {{ DateTime.now() }} - Current date/time {{ $now }} - Shorthand for current time {{ $today }} - Today's date {{ "2025-01-15".toDateTime().toFormat('dd/MM/yyyy') }} - "15/01/2025" {{ $now.toFormat('yyyy-MM-dd HH:mm:ss') }} - "2025-01-15 14:30:00" {{ $now.plus({days: 7}) }} - Add 7 days {{ $now.minus({hours: 2}) }} - Subtract 2 hours {{ $now.startOf('month') }} - First day of month {{ $now.endOf('week') }} - End of week {{ "2025-01-15".toDateTime().isWeekend }} - Check if weekend ### INLINE-ONLY HELPER FUNCTIONS: {{ $if($json.age >= 18, "Adult", "Minor") }} {{ $ifEmpty($json.name, "Unknown") }} {{ $max(10, 20, 30) }} - Returns 30 {{ $min(10, 20, 30) }} - Returns 10 {{ Math.round($json.value * 100) / 100 }} - Round to 2 decimals {{ Math.floor($json.price) }} - Round down {{ Math.ceil($json.price) }} - Round up ### ARRAY/STRING OPERATIONS: {{ $json.tags.join(", ") }} - Array to string {{ $json.text.split(",") }} - String to array {{ $json.items.length }} - Array/string length {{ $json.text.substring(0, 100) }} - First 100 chars {{ $json.name.toLowerCase() }} - Lowercase {{ $json.name.toUpperCase() }} - Uppercase {{ $json.text.replace("old", "new") }} - Replace text ### CHAINING METHODS: {{ $json.email.toLowerCase().trim().isEmail() ? $json.email : "invalid" }} {{ $json.tags.removeDuplicates().join(", ").toUpperCase() }} {{ $('HTTP Request').item.json.data.filter(d => d.active).length }} ### WORKING WITH ARRAYS: {{ $json.items.map(item => item.name).join(", ") }} {{ $json.users.filter(u => u.age > 18).length }} {{ $json.prices.reduce((sum, p) => sum + p, 0) }} ### IIFE PATTERN - CONVERT CODE NODE TO EXPRESSION: Use IIFE (Immediately Invoked Function Expression) for complex logic in expressions that would normally require Code Node. BASIC IIFE STRUCTURE: {{(() => { /* multi-line logic here */ return result; })()}} MULTI-STEP OPERATIONS: {{(() => { const data = $input.item.json; const processed = data.value * 2; const formatted = processed.toFixed(2); return formatted; })()}} COMPLEX ARRAY OPERATIONS: {{(() => { const arr = $input.item.json.myArray; return arr.filter(item => item.value > 10).map(item => item.name); })()}} COMPLEX CONDITIONALS: {{(() => { const value = $input.item.json.value; if (value > 100) return 'Very High'; if (value > 50) return 'High'; if (value > 25) return 'Medium'; return 'Low'; })()}} COMPLEX DATE MANIPULATION: {{(() => { const date = new Date($input.item.json.dateField); date.setDate(date.getDate() + 7); return date.toISOString(); })()}} COMPLEX STRING PROCESSING: {{(() => { const text = $input.item.json.text; return text.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); })()}} COMPLEX CALCULATIONS: {{(() => { const nums = $input.item.json.numbers; const sum = nums.reduce((a, b) => a + b, 0); const avg = sum / nums.length; return { sum, average: avg, rounded: Math.round(avg) }; })()}} COMPLEX OBJECT OPERATIONS: {{(() => { const data = $input.item.json; return Object.keys(data).filter(key => data[key] !== null).reduce((obj, key) => { obj[key] = data[key]; return obj; }, {}); })()}} ERROR HANDLING WITH TRY-CATCH: {{(() => { try { return JSON.parse($input.item.json.data); } catch (error) { return { error: error.message }; } })()}} IIFE RULES: - Use $input.item.json in IIFE patterns (not $json) - Must be single line in expression field (format for readability here) - Always wrap in double curly braces {{ }} - Arrow function must be immediately invoked with () - Can use variables, loops, conditionals inside - Must have explicit return statement - Use for logic too complex for simple expressions WHEN TO USE IIFE: - Multiple operations needed - Variable declarations required - Complex conditionals (multiple if/else) - Try-catch blocks needed - Loops or iterations required - Complex data transformations - When Code Node logic needs to be in expression ### NULL SAFETY: {{ $json.user?.email || "no-email@example.com" }} {{ $json.optional?.nested?.field ?? "default" }} {{ $json.maybeArray || [] }} ### JSON PARSING/STRINGIFYING: {{ JSON.parse($json.jsonString) }} {{ JSON.stringify($json.object) }} {{ JSON.stringify($json.data, null, 2) }} - Pretty print ### SPECIAL VARIABLES: {{ $itemIndex }} - Current item index (0-based) {{ $workflow.name }} - Workflow name {{ $workflow.id }} - Workflow ID {{ $execution.id }} - Execution ID {{ $execution.mode }} - 'test' or 'production' {{ $env.MY_VARIABLE }} - Environment variable {{ $vars.myGlobalVar }} - Global variable ## KEY WARNINGS CODE NODE: - NEVER wrap main code in functions - Code executes at script level - ONLY ONE return statement - Must be at end of top-level code - n8n context ($input, $workflow, etc.) only available at top level - Helper functions are OK but main execution stays at top level - NEVER use $items() - causes immediate failure - NEVER assume Python has network/file access - ALWAYS validate input data exists before accessing - ALWAYS return proper structure [{json: {}}] - NEVER use inline-only methods ($if, $max, $min) in Code node - ALWAYS use $('NodeName').all() not .item for multiple items - n8n Code Nodes are SCRIPTS not FUNCTIONS - execute top to bottom EXPRESSIONS: - ALWAYS use {{ }} - missing braces = literal text - NEVER use line breaks - must be single line - NEVER use $items() - use $('NodeName').all() - Check if field exists before accessing deep properties - Remember expressions are JavaScript - use JS methods - Test with sample data before production - Use optional chaining (?.) for nullable fields SIMPLE VS COMPLEX EXPRESSIONS: - Simple {{ }}: Direct value access, basic math, simple concatenation, single operations - Complex IIFE {{(() => {})()}}: Multiple operations, loops, variables, try-catch, complex conditionals - IIFE allows Code Node logic in expression format - powerful for complex transformations - Use IIFE when logic exceeds single operation complexity - IIFE is bridge between Code Node and Expression - same logic different format