n8n-best-practices
Use when encountering n8n workflow issues, Code node errors, HTTP requests failing, data flow problems, environment variables not working, JSON parsing errors, or need n8n development patterns and debugging strategies
$ Installer
git clone https://github.com/majiayu000/claude-skill-registry /tmp/claude-skill-registry && cp -r /tmp/claude-skill-registry/skills/development/n8n-best-practices ~/.claude/skills/claude-skill-registry// tip: Run this command in your terminal to install the skill
name: n8n-best-practices description: Use when encountering n8n workflow issues, Code node errors, HTTP requests failing, data flow problems, environment variables not working, JSON parsing errors, or need n8n development patterns and debugging strategies
n8n Best Practices
When to use this skill: Any time you're working with n8n workflows and encounter errors, unexpected behavior, or need guidance on implementation patterns.
Critical Knowledge Base
🚨 ES5 Syntax Only in Code Nodes
n8n Code nodes only support ES5 JavaScript. Modern ES6+ syntax will fail.
❌ DO NOT USE:
// Arrow functions
const process = (item) => item.value;
// Template literals
const url = `https://api.example.com/${id}`;
// const/let
const value = 123;
// Destructuring
const { name, age } = person;
// Spread operator in function calls
Math.max(...numbers);
✅ USE INSTEAD:
// Regular functions
var process = function(item) {
return item.value;
};
// String concatenation
var url = 'https://api.example.com/' + id;
// var only
var value = 123;
// Manual assignment
var name = person.name;
var age = person.age;
// apply() for spread
Math.max.apply(null, numbers);
// Object spread alternative
var merged = Object.assign({}, obj1, obj2);
🌐 HTTP Requests in Code Nodes
CRITICAL: $http and axios are NOT available in Code nodes.
❌ WRONG:
const response = await $http.request({url: 'https://api.example.com'});
const axios = require('axios');
✅ CORRECT - Use Native HTTPS:
var https = require('https');
function makeRequest(url, options) {
return new Promise(function(resolve, reject) {
var req = https.request(options, function(res) {
var data = '';
res.on('data', function(chunk) { data += chunk; });
res.on('end', function() {
resolve({statusCode: res.statusCode, body: data});
});
});
req.on('error', reject);
req.end();
});
}
// Usage
var result = await makeRequest('example.com', {
hostname: 'example.com',
path: '/api/endpoint',
method: 'POST',
headers: {'Content-Type': 'application/json'}
});
🔐 Environment Variables Configuration
CRITICAL: Variables must be explicitly exported, not just sourced.
❌ WRONG:
source .env.local
pnpm start
# Variables will be undefined in Code nodes!
✅ CORRECT:
#!/bin/bash
export NOTION_API_KEY=$(grep NOTION_API_KEY .env.local | cut -d '=' -f2)
export QWEN_API_KEY=$(grep QWEN_API_KEY .env.local | cut -d '=' -f2)
export NODE_FUNCTION_ALLOW_BUILTIN=*
export N8N_BLOCK_ENV_ACCESS_IN_NODE=false
pnpm start
Access in Code nodes:
var apiKey = process.env.NOTION_API_KEY; // Not $env
📦 gzip Compression Issues
Problem: HTTP requests with gzip compression return garbled data.
❌ WRONG:
headers: {
'Accept-Encoding': 'gzip, deflate'
}
// Returns: �������
✅ CORRECT:
headers: {
'Content-Type': 'application/json'
// DO NOT include Accept-Encoding header
}
🔄 Data Flow Patterns
Always preserve upstream data:
✅ CORRECT:
return {
json: Object.assign({}, $input.item.json, {
newField: newValue
})
};
❌ WRONG:
return {
json: {
newField: newValue // Loses all previous data!
}
};
📋 JSON Parsing Best Practices
❌ WRONG:
var data = JSON.parse(response);
// May return undefined without error
✅ CORRECT:
function safeJSONParse(text) {
try {
var parsed = JSON.parse(text);
if (parsed && typeof parsed === 'object') {
return parsed;
}
throw new Error('Parsed value is not an object');
} catch (e) {
throw new Error('JSON parsing failed: ' + e.message);
}
}
var data = safeJSONParse(response);
🔧 Code Node Sandbox Configuration
macOS launchd service:
<key>EnvironmentVariables</key>
<dict>
<key>NODE_FUNCTION_ALLOW_BUILTIN</key>
<string>*</string>
</dict>
Shell script:
export NODE_FUNCTION_ALLOW_BUILTIN=*
n8n start
🐛 Common Pitfalls
1. Aggregate Node Array Wrapping
// Aggregate converts: {field: value} → {field: [value]}
var data = $input.first().json;
var actualValue = data.field[0]; // Must access array
2. Split Into Batches Data Loss
// ❌ WRONG: Loses data
return items.map(function(item) {
return {json: {processed: true}};
});
// ✅ CORRECT: Preserves data
return items.map(function(item) {
return {
json: Object.assign({}, item.json, {processed: true})
};
});
3. require() Module Access
// Only available if NODE_FUNCTION_ALLOW_BUILTIN=*
var https = require('https'); // ✅ Works
var axios = require('axios'); // ❌ Not available
Quick Reference
When Code node fails:
- Check ES5 syntax (no arrow functions, template literals)
- Verify environment variables are exported
- Use
require('https')not$http - Remove
Accept-Encodingheader for gzip issues
When data is lost:
- Always spread previous data:
Object.assign({}, $input.item.json, newData) - Check Aggregate node array wrapping
- Verify Split Into Batches preserves data
When environment variables are undefined:
- Use
export, notsource - Access with
process.env.VAR, not$env.VAR - Set
N8N_BLOCK_ENV_ACCESS_IN_NODE=false
Full Documentation
For complete details, examples, and advanced patterns, see:
/mnt/d/work/n8n_agent/n8n-skills/n8n-best-practices/README.md
Repository
