Code 노드 — JavaScript/Python으로 자유자재 데이터 변환

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 — 워크플로우에 두뇌를 달자

지금까지의 워크플로우는 직선이었다. 이제 "만약 ~이라면?"이라는 조건을 추가하여 갈림길을 만들고, 나뉜 길을 다시 합치는 법을 배운다.