Code 노드 — JavaScript/Python으로 자유자재 데이터 변환
n8n의 비주얼 노드가 90%의 문제를 해결한다면, 나머지 10%는 Code 노드가 해결한다. JavaScript와 Python을 n8n 안에서 직접 실행할 수 있는 이 노드가 "한계 없는 자동화"의 열쇠다.
Code 노드란?
Code 노드는 n8n 워크플로우 안에서 프로그래밍 코드를 직접 실행하는 노드다.
| 특징 | 설명 |
|---|---|
| 지원 언어 | JavaScript (Node.js), Python |
| 실행 환경 | n8n 서버 위에서 직접 실행 |
| 접근 가능 | 이전 노드 데이터, 환경 변수, 외부 모듈 |
| 용도 | 복잡한 데이터 변환, 커스텀 로직, 계산 |
언제 Code 노드를 쓰는가?
| 상황 | 표준 노드 | Code 노드 |
|---|---|---|
| 단순 필드 매핑 | ✅ Edit Fields | ❌ 과도함 |
| true/false 분기 | ✅ IF 노드 | ❌ 과도함 |
| 복잡한 배열 변환 | ❌ 어려움 | ✅ 적합 |
| 커스텀 해싱/암호화 | ❌ 불가 | ✅ 적합 |
| 정규식 문자열 처리 | ❌ 제한적 | ✅ 적합 |
| 여러 아이템 집계 | ❌ 제한적 | ✅ 적합 |
| 외부 API 응답 구조 변환 | △ 가능하나 복잡 | ✅ 적합 |
💡 원칙: 표준 노드로 가능하면 표준 노드를 쓰자. Code 노드는 표준 노드로 힘든 일에만 사용한다. 비주얼 워크플로우의 가독성을 유지하기 위함이다.
실행 모드: Run Once vs Run for Each Item
Code 노드에는 두 가지 실행 모드가 있다. 이 차이를 정확히 이해해야 한다.
Run Once for All Items (전체 한 번 실행)
모든 아이템을 한꺼번에 받아서 처리한다.
// 입력: 아이템 3개가 들어온 경우
// 코드는 1번만 실행되고, $input.all()로 전체를 받는다
const items = $input.all();
// items.length === 3
return items.map(item => ({
json: {
name: item.json.name.toUpperCase(),
processed: true
}
}));
적합한 경우: - 아이템 간 비교, 정렬, 집계가 필요할 때 - 전체 데이터를 기반으로 계산할 때 - 아이템을 합치거나 분리할 때
Run Once for Each Item (아이템별 실행)
아이템 하나씩 개별적으로 처리한다.
// 입력: 아이템 3개가 들어온 경우
// 코드는 3번 실행된다 (아이템마다 1번)
return {
json: {
name: $input.item.json.name.toUpperCase(),
processed: true
}
};
적합한 경우: - 각 아이템을 독립적으로 처리할 때 - 코드가 간단하고 아이템 간 관계가 없을 때
모드 선택 가이드
| 하고 싶은 것 | 모드 |
|---|---|
| 배열 정렬 | Run Once for All Items |
| 데이터 집계 (합계, 평균) | Run Once for All Items |
| 중복 제거 | Run Once for All Items |
| 각 아이템에 필드 추가 | Run Once for Each Item |
| 문자열 변환 | Run Once for Each Item |
| 날짜 파싱 | Run Once for Each Item |
JavaScript 실전 예제
예제 1: 배열 필터링 + 정렬
// 가격이 10,000원 이상인 상품만 필터링하고 가격순 정렬
const items = $input.all();
const filtered = items
.filter(item => item.json.price >= 10000)
.sort((a, b) => b.json.price - a.json.price);
return filtered.map(item => ({
json: {
...item.json,
priceFormatted: item.json.price.toLocaleString('ko-KR') + '원'
}
}));
예제 2: 중복 제거
// 이메일 기준으로 중복 아이템 제거
const items = $input.all();
const seen = new Set();
const unique = [];
for (const item of items) {
if (!seen.has(item.json.email)) {
seen.add(item.json.email);
unique.push(item);
}
}
return unique;
예제 3: 데이터 집계
// 카테고리별 매출 합계 계산
const items = $input.all();
const summary = {};
for (const item of items) {
const cat = item.json.category;
if (!summary[cat]) {
summary[cat] = { count: 0, total: 0 };
}
summary[cat].count += 1;
summary[cat].total += item.json.amount;
}
return Object.entries(summary).map(([category, data]) => ({
json: {
category,
count: data.count,
total: data.total,
average: Math.round(data.total / data.count)
}
}));
예제 4: 정규식 문자열 처리
// HTML 태그 제거 + 이메일 추출
const text = $input.item.json.content;
// HTML 태그 제거
const plainText = text.replace(/<[^>]*>/g, '');
// 이메일 추출
const emails = text.match(/[\w.-]+@[\w.-]+\.\w+/g) || [];
// 전화번호 추출 (한국)
const phones = text.match(/01[0-9]-?\d{3,4}-?\d{4}/g) || [];
return {
json: {
plainText,
emails,
phones,
emailCount: emails.length
}
};
예제 5: 날짜 계산
// 가입일로부터 경과 일수 계산
const items = $input.all();
return items.map(item => {
const signupDate = new Date(item.json.created_at);
const now = new Date();
const diffDays = Math.floor((now - signupDate) / (1000 * 60 * 60 * 24));
return {
json: {
...item.json,
daysSinceSignup: diffDays,
isNewUser: diffDays <= 30,
tier: diffDays > 365 ? 'VIP' : diffDays > 90 ? 'Regular' : 'New'
}
};
});
Python 모드
Code 노드에서 언어를 Python으로 전환할 수 있다. Python이 더 익숙하다면 이 모드를 사용하자.
Python 기본 구조
# Run Once for All Items
items = _input.all()
result = []
for item in items:
result.append({
"json": {
"name": item.json["name"].upper(),
"processed": True
}
})
return result
Python 예제: 텍스트 분석
# 텍스트에서 키워드 빈도 분석
import re
from collections import Counter
text = _input.first().json["content"]
# 단어 추출
words = re.findall(r'\b\w{2,}\b', text.lower())
# 빈도 계산 (상위 10개)
counter = Counter(words).most_common(10)
return [{
"json": {
"keyword": word,
"count": count
}
} for word, count in counter]
JavaScript vs Python 선택
| 기준 | JavaScript | Python |
|---|---|---|
| 익숙한 언어 | JS 개발자 | Python 개발자 |
| 성능 | 약간 빠름(네이티브) | 약간 느림(브릿지) |
| 외부 모듈 | npm (제한적) | pip (제한적) |
| 데이터 처리 | 충분 | pandas 등 강력 |
| 공식 지원 | 1급 지원 | 1급 지원 |
내장 변수와 유틸리티
Code 노드에서 사용할 수 있는 n8n 전용 변수들:
JavaScript
// 입력 데이터
$input.all() // 모든 아이템 (배열)
$input.first() // 첫 번째 아이템
$input.last() // 마지막 아이템
$input.item // 현재 아이템 (Each Item 모드)
// 다른 노드 참조
$('NodeName').all() // 특정 노드의 전체 출력
$('NodeName').first() // 특정 노드의 첫 아이템
// 환경/변수
$env // 환경 변수 객체
$vars // n8n 전역 변수
$execution.id // 현재 실행 ID
$workflow.name // 워크플로우 이름
// 유틸리티
$now // 현재 DateTime (Luxon)
$today // 오늘 날짜 (Luxon)
Python
# 입력 데이터
_input.all() # 모든 아이템 (리스트)
_input.first() # 첫 번째 아이템
_input.last() # 마지막 아이템
_input.item # 현재 아이템 (Each Item 모드)
# 다른 노드 참조
_node["NodeName"].all() # 특정 노드의 전체 출력
# 환경/변수
_env # 환경 변수
_vars # n8n 전역 변수
_execution.id # 현재 실행 ID
외부 모듈 사용
JavaScript 내장 모듈
n8n의 Code 노드에서는 일부 Node.js 내장 모듈을 바로 사용할 수 있다:
const crypto = require('crypto');
const { DateTime } = require('luxon');
// SHA-256 해시 생성
const hash = crypto
.createHash('sha256')
.update($input.item.json.password)
.digest('hex');
return { json: { hash } };
npm 모듈 사용 (고급)
셀프호스팅 환경에서는 N8N_NODE_MODULES_TO_ALLOW 환경 변수로 추가 모듈을 허용할 수 있다:
# docker-compose.yml
environment:
- NODE_FUNCTION_ALLOW_EXTERNAL=lodash,moment
const _ = require('lodash');
const items = $input.all();
const grouped = _.groupBy(items.map(i => i.json), 'category');
return Object.entries(grouped).map(([key, values]) => ({
json: { category: key, items: values }
}));
반환값 규칙
Code 노드의 반환값은 반드시 n8n이 이해할 수 있는 형식이어야 한다.
올바른 반환
// 단일 아이템
return { json: { key: "value" } };
// 여러 아이템
return [
{ json: { name: "A" } },
{ json: { name: "B" } },
{ json: { name: "C" } }
];
// 아이템 필터링 (빈 배열 = 0개 출력)
return [];
잘못된 반환
// ❌ json 키가 없음
return { name: "value" };
// ❌ 배열이 아닌 문자열
return "hello";
// ❌ json 값이 객체가 아님
return { json: "string" };
아이템 제거 (필터링)
특정 조건의 아이템만 통과시키려면:
const items = $input.all();
return items.filter(item => item.json.status === 'active');
아이템 추가 (증식)
하나의 아이템에서 여러 아이템을 만들려면:
// 하나의 주문에서 여러 상품 아이템을 생성
const order = $input.first().json;
return order.products.map(product => ({
json: {
orderId: order.id,
productName: product.name,
quantity: product.qty,
price: product.price
}
}));
에러 핸들링
try-catch 사용
try {
const data = JSON.parse($input.item.json.rawData);
return { json: { parsed: data, success: true } };
} catch (error) {
return { json: { error: error.message, success: false } };
}
의도적 에러 발생
워크플로우를 중단하고 싶을 때:
if (!$input.item.json.requiredField) {
throw new Error('필수 필드가 누락되었습니다: requiredField');
}
📝 정리
- [x] Code 노드: n8n 안에서 JavaScript/Python 코드를 직접 실행하는 노드
- [x] 실행 모드: Run Once(전체 처리) vs Run for Each Item(개별 처리)
- [x] 반환 규칙: 반드시
{ json: {...} }형태 또는 배열로 반환 - [x] 내장 변수:
$input,$env,$now,$('NodeName')등 활용 - [x] 사용 시점: 표준 노드로 힘든 복잡한 변환, 집계, 정규식 처리에 적합
다음 편 예고
9편: IF / Switch / Merge — 워크플로우에 두뇌를 달자
지금까지의 워크플로우는 직선이었다. 이제 "만약 ~이라면?"이라는 조건을 추가하여 갈림길을 만들고, 나뉜 길을 다시 합치는 법을 배운다.