n8n이란?

오픈소스 워크플로우 자동화 플랫폼 — AI와 400개 이상의 서비스를 코드 없이 연결하는 셀프호스팅 자동화 엔진 완전 가이드

⚡ 30초 퀵스타트
# Docker 한 줄로 즉시 실행
docker run -it --rm -p 5678:5678 -v ~/.n8n:/home/node/.n8n n8nio/n8n

# → http://localhost:5678 접속, 계정 생성 후 바로 사용

n8n이란 무엇인가?

n8n(발음: "n-eight-n" 또는 "nodemation")은 독일 스타트업 n8n GmbH가 2019년 공개한 오픈소스 워크플로우 자동화 플랫폼입니다. 코드 없이 시각적 에디터로 자동화를 구축하면서도, 필요하면 JavaScript/Python 코드를 자유롭게 삽입할 수 있는 로우코드(Low-Code) 접근 방식이 특징입니다.

2024~2025년 AI 붐과 함께 n8n은 LLM 기반 AI 에이전트 워크플로우를 가장 쉽게 구축할 수 있는 플랫폼으로 주목받고 있습니다. Claude, OpenAI, Gemini 등 주요 AI API와의 기본 통합을 제공하며, 메모리·도구 사용·RAG 파이프라인까지 노드 조합으로 완성할 수 있습니다.

핵심 특징

  • 셀프호스팅 우선: 데이터를 자체 서버에서 처리 — 프라이버시와 비용 절감
  • 공정 코드 라이선스: Sustainable Use License — 영리 목적 SaaS 재판매 제외 시 무료
  • 400+ 통합 노드: Slack, GitHub, PostgreSQL, HTTP Request, AI 노드 등
  • 시각적 에디터: 드래그 앤 드롭으로 워크플로우 설계
  • 코드 삽입 가능: Code 노드로 JS/Python 코드 직접 실행
  • AI 네이티브: AI Agent, LLM Chain, 벡터 스토어 노드 기본 제공
  • 다양한 트리거: Webhook, Cron, 이벤트, 수동 실행
  • 실행 이력: 각 실행의 입력/출력 데이터를 시각적으로 확인
  • 팀 협업: 사용자 권한(Owner/Member/Viewer), 프로젝트 분리
  • 템플릿 마켓플레이스: 900개+ 공개 워크플로우 템플릿 즉시 사용
트리거 / 소스 Webhook Cron Schedule GitHub Event Slack Message Email / Form 수동 실행 n8n 워크플로우 엔진 Trigger 노드 이벤트 감지 Transform 노드 데이터 변환/필터 AI Agent 노드 LLM + 도구 실행 Code 노드 JS / Python 실행 IF / Switch 조건 분기 Loop / Split 반복 처리 Sub-Workflow / Error Handler 모듈화 · 에러 복구 액션 / 대상 Slack 전송 Email 전송 DB 저장 HTTP 호출 GitHub PR AI 응답 반환

n8n 아키텍처: 외부 트리거 → 워크플로우 노드 체인 → 액션 대상

n8n vs 다른 자동화 도구 비교

항목n8nZapierMake (Integromat)AirflowTemporal
호스팅셀프호스팅(무료)/CloudCloud 전용Cloud 전용셀프호스팅셀프호스팅/Cloud
비용셀프호스팅 무료$20~$69+/월$9~$29+/월인프라만인프라만
코드 작성선택적(JS/Python)제한적제한적Python 필수Go/TypeScript
AI 통합전용 AI 노드 다수기본 OpenAIOpenAI 지원커스텀 코드커스텀 코드
데이터 프라이버시완전 자체 보관Zapier 경유Make 경유완전 자체완전 자체
학습 난이도중간쉬움중간높음매우 높음
오픈소스✅ Sustainable Use✅ Apache 2.0✅ MIT
실시간 이벤트✅ Webhook✅ (제한)제한적
적합 대상개발자·기업 자동화비개발자비개발자데이터 엔지니어백엔드 개발자
🎯 n8n이 최적인 상황
  • 민감한 데이터(고객 정보, 소스코드)를 외부 서버에 보내고 싶지 않을 때
  • AI 에이전트 워크플로우를 빠르게 프로토타이핑할 때
  • 월 구독 비용을 절감하고 싶을 때 (팀 규모 확장 시)
  • 커스텀 로직이 필요하지만 전체를 코드로 짜기엔 부담될 때
  • 복잡한 조건 분기, 루프, 멀티스텝 자동화가 필요할 때

설치 방법

방법 1: Docker (가장 추천)

# 기본 실행 (데이터 보존 포함)
docker run -d \
  --name n8n \
  -p 5678:5678 \
  -v ~/.n8n:/home/node/.n8n \
  --restart unless-stopped \
  n8nio/n8n

# 특정 버전 고정 (운영 환경 권장)
docker run -d \
  --name n8n \
  -p 5678:5678 \
  -v ~/.n8n:/home/node/.n8n \
  --restart unless-stopped \
  n8nio/n8n:2.16.1   # 버전 명시

방법 2: Docker Compose (운영 환경)

# docker-compose.yml
version: '3.8'
services:
  n8n:
    image: n8nio/n8n:2.16.1
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - WEBHOOK_URL=https://n8n.yourdomain.com
      - GENERIC_TIMEZONE=Asia/Seoul
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${DB_PASSWORD}
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      postgres:
        condition: service_healthy

  postgres:
    image: postgres:15-alpine
    restart: unless-stopped
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n"]
      interval: 10s
      retries: 5

volumes:
  n8n_data:
  postgres_data:
# .env 파일
N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)
DB_PASSWORD=$(openssl rand -hex 16)

# 실행
docker compose up -d
docker compose logs -f n8n

방법 3: npm (로컬 개발)

# Node.js 20.19+ 필요
node --version   # v20.19.0 이상 확인

npm install -g n8n

# 실행
n8n start

# 터널링으로 외부 Webhook 테스트 (개발용)
n8n start --tunnel

주요 환경 변수 전체 참조

환경 변수기본값설명
N8N_PORT5678서버 포트
N8N_HOSTlocalhost서버 호스트 (0.0.0.0 = 모든 인터페이스)
N8N_PROTOCOLhttphttp 또는 https
WEBHOOK_URL-외부 Webhook URL (Nginx 뒤 배치 시)
N8N_ENCRYPTION_KEY자동 생성자격증명 암호화 키 (운영 필수 고정)
N8N_USER_MANAGEMENT_JWT_SECRET자동JWT 서명 키
DB_TYPEsqlitesqlite / postgresdb / mysqldb
DB_POSTGRESDB_*-PostgreSQL 연결 정보
EXECUTIONS_MODEregularregular / queue (대용량)
EXECUTIONS_DATA_MAX_AGE336 (2주)실행 이력 보관 시간
EXECUTIONS_DATA_PRUNEtrue오래된 이력 자동 삭제
EXECUTIONS_DATA_PRUNE_MAX_COUNT10000최대 보관 실행 수
N8N_CONCURRENCY_PRODUCTION_LIMIT-1 (무제한)동시 실행 워크플로우 수
N8N_LOG_LEVELinfoerror/warn/info/verbose/debug
N8N_LOG_OUTPUTconsoleconsole / file
GENERIC_TIMEZONEUTC타임존 (예: Asia/Seoul)
N8N_DIAGNOSTICS_ENABLEDtrue원격 진단 전송 (운영 시 false 권장)
N8N_VERSION_NOTIFICATIONS_ENABLEDtrue버전 알림 표시
N8N_TEMPLATES_ENABLEDtrue템플릿 마켓플레이스 표시
NODE_FUNCTION_ALLOW_BUILTIN*Code 노드에서 허용할 Node.js 내장 모듈
NODE_FUNCTION_ALLOW_EXTERNAL-Code 노드에서 허용할 npm 패키지 (쉼표 구분)
N8N_PAYLOAD_SIZE_MAX16 (MB)최대 요청 크기
💡 Code 노드에서 외부 npm 패키지 사용
# 특정 패키지 허용
NODE_FUNCTION_ALLOW_EXTERNAL=lodash,moment,axios,cheerio

# 모든 패키지 허용 (보안 주의)
NODE_FUNCTION_ALLOW_EXTERNAL=*

허용된 패키지는 Code 노드에서 require('lodash')로 바로 사용 가능합니다.

핵심 개념

n8n 워크플로우 실행 구조 Trigger 노드 Webhook / Schedule / Event 데이터 변환 Set · Code · Function JSON 데이터 흐름 조건 분기 IF · Switch · Filter $json, $items() 표현식 true false AI Agent 노드 Claude / GPT / Gemini HTTP Request 외부 API 연동 결과 저장 / 알림

워크플로우(Workflow)

워크플로우는 n8n의 기본 단위입니다. 노드(Node)연결(Connection)로 이어진 방향 그래프입니다.

  • 활성(Active): Trigger 노드가 이벤트를 감지하면 자동 실행
  • 비활성(Inactive): 수동 실행 / 테스트만 가능
  • 워크플로우 설정: 에러 워크플로우 지정, 타임존, 실행 제한, 저장 정책

노드(Node) 분류

분류역할주요 예시
Trigger워크플로우 시작 이벤트Webhook, Schedule, Email Trigger, GitHub Trigger, Chat Trigger
Action데이터 조회·변경·전송HTTP Request, Slack, Gmail, PostgreSQL, Google Sheets
Data Transform데이터 가공·변환Code, Set, Edit Fields, Filter, Sort, Aggregate
Flow Control실행 흐름 제어IF, Switch, Loop, Merge, Wait, SplitInBatches
AI / LangChainLLM·에이전트 실행AI Agent, Basic LLM Chain, OpenAI, Anthropic
Helper유틸리티Date & Time, Crypto, HTML Extract, RSS Read

데이터 구조 — 아이템(Item)과 Binary

노드 간 전달 데이터는 아이템(Item) 배열입니다. 각 아이템은 json(구조화 데이터)과 선택적으로 binary(파일/이미지 등) 필드를 가집니다.

// 아이템 배열 구조
[
  {
    "json": {
      "id": 1,
      "name": "홍길동",
      "email": "hong@example.com"
    }
  },
  {
    "json": { "id": 2, "name": "김철수" },
    "binary": {
      "data": {
        "data": "base64EncodedContent...",
        "mimeType": "application/pdf",
        "fileName": "report.pdf",
        "fileSize": 102400
      }
    }
  }
]
// Code 노드에서 Binary 데이터 처리
const item = $input.first();

// binary 존재 확인
if (item.binary?.data) {
  const { mimeType, fileName } = item.binary.data;
  console.log(`파일: ${fileName} (${mimeType})`);
}

// Binary → Buffer 변환
const buffer = Buffer.from(item.binary.data.data, 'base64');

return [{ json: { size: buffer.length } }];

Paired Items (아이템 페어링)

여러 노드의 출력을 Merge할 때, 각 아이템이 어느 원본 아이템에서 나왔는지 추적하는 메커니즘입니다. Merge by Key 모드에서 올바른 JOIN을 위해 중요합니다.

// Code 노드에서 pairedItem 명시적 설정
return $input.all().map((item, idx) => ({
  json: {
    ...item.json,
    processed: true
  },
  pairedItem: { item: idx }   // 원본 아이템 인덱스 연결
}));

표현식(Expression) 완전 가이드

n8n 노드 필드에 {{ }} 구문으로 동적 값을 삽입합니다. 내부적으로 tmpl.js 템플릿 엔진을 사용하며, 단일 JavaScript 표현식을 지원합니다.

내장 변수 전체 목록

변수타입설명
$jsonobject현재 노드 입력 아이템의 json 필드
$inputobject현재 노드 전체 입력 (.all(), .first(), .last(), .item(n))
$items("노드명")array특정 이름의 노드 출력 배열
$node["노드명"].jsonobject특정 노드의 첫 번째 아이템 json
$node["노드명"].contextobjectLoop 노드의 반복 상태(noItemsLeft, currentRunIndex 등)
$envobject환경 변수 ($env.MY_VAR)
$varsobjectn8n 전역 변수 (UI에서 설정)
$workflowobject워크플로우 메타데이터 (id, name, active)
$executionobject실행 정보 (id, mode, resumeUrl)
$nowLuxon DateTime현재 시각 (Luxon 객체)
$todayLuxon DateTime오늘 자정 (Luxon 객체)
$prevNodeobject이전 노드 정보 (name, outputIndex, runIndex)
$runIndexnumberLoop 내 현재 반복 인덱스 (0부터)
$itemIndexnumber현재 처리 중인 아이템 인덱스 (0부터)
$parameterobject노드 파라미터 값 참조
$secretobjectn8n Vault 시크릿 (Enterprise)

Luxon 날짜/시간 처리

n8n은 Luxon 라이브러리를 내장하여 날짜/시간 처리를 지원합니다.

// 현재 시각
{{ $now.toISO() }}                          // "2026-02-18T03:00:00.000+09:00"
{{ $now.toFormat('yyyy-MM-dd HH:mm') }}     // "2026-02-18 03:00"
{{ $now.toFormat('yyyy년 MM월 dd일') }}      // "2026년 02월 18일"

// 날짜 계산
{{ $now.plus({ days: 7 }).toISODate() }}    // 7일 후 날짜
{{ $now.minus({ hours: 1 }).toISO() }}      // 1시간 전
{{ $now.startOf('month').toISODate() }}     // 이번 달 1일
{{ $now.endOf('month').toISODate() }}       // 이번 달 말일

// Unix 타임스탬프 변환
{{ $now.toSeconds() }}                      // Unix 초
{{ $now.toMillis() }}                       // Unix 밀리초
{{ DateTime.fromSeconds($json.timestamp).toISO() }}  // 역변환

// 요일 확인
{{ $now.weekday }}                          // 1(월)~7(일)
{{ $now.weekdayLong }}                      // "Monday" 등

// 기간 계산
{{ $now.diff(DateTime.fromISO($json.createdAt), 'days').days.toFixed(0) }} 일 경과

문자열·배열 조작

// 문자열
{{ $json.name.toUpperCase() }}
{{ $json.email.split('@')[0] }}              // 이메일 앞부분
{{ $json.text.substring(0, 100) + '...' }}  // 100자 자르기
{{ $json.html.replace(/<[^>]*>/g, '') }}  // HTML 태그 제거
{{ $json.url.includes('https') ? '보안' : '비보안' }}

// 배열
{{ $json.tags.join(', ') }}
{{ $json.items.length }}
{{ $json.scores.reduce((a, b) => a + b, 0) / $json.scores.length }}  // 평균
{{ $json.items.filter(i => i.active).map(i => i.name).join(', ') }}

// JSON
{{ JSON.stringify($json.metadata) }}
{{ JSON.parse($json.configStr).timeout }}

고급 표현식 패턴

// 다른 노드 아이템 참조
{{ $items("HTTP Request")[0].json.data }}
{{ $items("PostgreSQL").length }}

// Nullish coalescing (값 없으면 기본값)
{{ $json.description ?? '설명 없음' }}
{{ $json.user?.email ?? 'unknown@example.com' }}

// 복잡한 조건
{{ ['admin', 'manager'].includes($json.role) ? '관리자' : '일반 사용자' }}

// Loop 노드 내 반복 정보
{{ $node["SplitInBatches"].context.currentRunIndex }}  // 현재 배치 번호
{{ $node["SplitInBatches"].context.noItemsLeft }}      // 마지막 배치 여부

// 실행 메타데이터
{{ $execution.id }}          // 실행 고유 ID
{{ $workflow.name }}         // 워크플로우 이름
{{ $execution.mode }}        // "trigger" | "manual" | "retry"

트리거 노드 완전 가이드

Webhook Trigger

외부 시스템이 HTTP 요청을 보내면 워크플로우를 시작합니다. n8n에서 가장 많이 사용되는 트리거입니다.

# Webhook 노드 설정 상세

## 기본 설정
HTTP Method: GET / POST / PUT / PATCH / DELETE / HEAD (복수 선택 가능)
Path: my-webhook             # https://n8n.example.com/webhook/my-webhook
Response Mode:
  - Immediately           # 즉시 200 OK 반환 (비동기)
  - When Last Node Finishes  # 워크플로우 완료 후 응답 (동기)
  - Using 'Respond to Webhook' Node  # 원하는 노드에서 응답

## 인증 옵션
Authentication: None / Basic Auth / Header Auth / JWT Auth

## 요청 데이터 접근
{{ $json.body }}         # POST 본문
{{ $json.query }}        # 쿼리 파라미터
{{ $json.headers }}      # HTTP 헤더
{{ $json.params }}       # URL 경로 파라미터

## 테스트 URL (비활성 상태) vs 운영 URL (활성 상태)
테스트: https://n8n.example.com/webhook-test/my-webhook
운영:   https://n8n.example.com/webhook/my-webhook
# Webhook 수신 데이터 구조 예시 (POST JSON)
{
  "body": { "user": "홍길동", "action": "signup" },
  "headers": {
    "content-type": "application/json",
    "x-signature": "sha256=abc123..."
  },
  "query": { "source": "email" },
  "params": {}
}

Schedule Trigger (Cron)

# 인터벌 방식
Trigger Interval: Minutes / Hours / Days / Weeks / Months
예) Every 30 minutes → 30분마다 실행

# 커스텀 Cron 표현식
Cron Expression: 0 9 * * 1-5
  ┬ ┬ ┬ ┬ ┬
  │ │ │ │ └─ 요일 (0=일, 1=월 ... 5=금, 6=토)
  │ │ │ └─── 월 (1-12)
  │ │ └───── 일 (1-31)
  │ └─────── 시 (0-23)
  └───────── 분 (0-59)

# 실용 예시
"0 9 * * 1-5"     → 평일 오전 9시
"0 0 1 * *"       → 매월 1일 자정
"0 */2 * * *"     → 2시간마다
"30 8 * * 1"      → 매주 월요일 8:30
"0 9,12,18 * * *" → 하루 3번 (9시, 12시, 18시)

기타 트리거 노드

트리거용도특이사항
Email Trigger (IMAP)새 이메일 수신 시 실행폴링 방식, 30~60초 간격
Chat Triggern8n 내장 채팅 UI 메시지웹 임베드 가능
Execute Workflow Trigger다른 워크플로우에서 호출서브워크플로우 필수
Error Trigger워크플로우 오류 발생 시에러 알림 워크플로우용
GitHub TriggerPR, Push, Issue 등 이벤트GitHub Webhook 자동 등록
Slack TriggerSlack 메시지/이벤트Bot Token + Event API
Form Triggern8n 내장 폼 제출별도 폼 UI 자동 생성
SSE TriggerServer-Sent Events 수신실시간 스트림 데이터
RabbitMQ Trigger메시지 큐 컨슈머AMQP 프로토콜
Kafka TriggerKafka 토픽 컨슈머대용량 이벤트 처리

핵심 노드 완전 레퍼런스

HTTP Request

# 주요 설정
Method: GET / POST / PUT / PATCH / DELETE / HEAD / OPTIONS
URL: https://api.example.com/{{ $json.resourceId }}

# Authentication
- None
- Header Auth: Authorization: Bearer {{ $env.API_TOKEN }}
- Basic Auth: username + password
- OAuth2: 자격증명으로 자동 토큰 갱신
- API Key: 쿼리 또는 헤더에 키 자동 삽입

# Body 전송 방식
Content Type: JSON / Form-Data / Form-URL-Encoded / Binary / RAW
JSON Body:
{
  "name": "{{ $json.name }}",
  "tags": {{ JSON.stringify($json.tags) }}
}

# 응답 처리
Response Format: JSON / Text / File / Auto-detect
Full Response: true → { status, headers, body } 포함

# 실패 처리
Continue on Fail: true      # 에러여도 계속 진행
Retry On Fail: true         # 자동 재시도
Max Tries: 3
Wait Between Tries (ms): 2000

# 타임아웃
Timeout: 10000   # 10초 (ms)

Code 노드

// 실행 모드 선택
// "Run Once for All Items" — 전체 아이템 배열을 한 번에 처리 (기본)
const items = $input.all();
const results = items.map(item => ({
  json: {
    ...item.json,
    upperName: item.json.name?.toUpperCase(),
    processedAt: $now.toISO(),
  }
}));
return results;

// "Run Once for Each Item" — 아이템마다 독립 실행
const { name, score } = $json;
return { json: { name, grade: score >= 90 ? 'A' : score >= 80 ? 'B' : 'C' } };

// Python 모드 (별도 설정)
# Python 표현식으로 데이터 처리
import json, datetime

items = _input.all()
result = []
for item in items:
    data = item['json']
    result.append({
        'json': {
            'name': data['name'].upper(),
            'processed': datetime.datetime.now().isoformat()
        }
    })
return result
// 자주 쓰는 Code 노드 패턴

// 1. 외부 npm 모듈 사용 (NODE_FUNCTION_ALLOW_EXTERNAL 필요)
const _ = require('lodash');
const items = $input.all().map(i => i.json);
const grouped = _.groupBy(items, 'category');
return Object.entries(grouped).map(([key, val]) => ({
  json: { category: key, count: val.length, items: val }
}));

// 2. CSV 파싱
const csv = $json.csvText;
const lines = csv.trim().split('\n');
const headers = lines[0].split(',');
return lines.slice(1).map(line => {
  const vals = line.split(',');
  return { json: Object.fromEntries(headers.map((h, i) => [h.trim(), vals[i]?.trim()])) };
});

// 3. 중복 제거
const seen = new Set();
return $input.all().filter(item => {
  const key = item.json.email;
  if (seen.has(key)) return false;
  seen.add(key);
  return true;
});

Flow Control 노드 상세

## IF 노드
조건 결합: AND / OR
연산자: Equal, Not Equal, Contains, Starts With, Ends With,
        Larger, Smaller, Regex Match, Is Empty, Is Not Empty

## Switch 노드
# 여러 조건 분기 (IF의 다중 버전)
Mode: Rules   → 각 Rule에 조건 설정, 해당 출력으로 분기
Mode: Expression → {{ $json.type }} 값으로 자동 분기
Fallback: 매치 없는 경우 출력

## SplitInBatches 노드
# 대량 아이템을 N개씩 묶어 순차 처리
Batch Size: 10          # 한 번에 10개씩
Options:
  Reset: false          # 루프 초기화 여부

# Loop 상태 확인 (다음 노드에서)
{{ $node["SplitInBatches"].context.noItemsLeft }}    # 마지막 배치?
{{ $node["SplitInBatches"].context.currentRunIndex }} # 현재 배치 번호

## Wait 노드
# 워크플로우 실행을 지정 시간 동안 일시 정지
Resume: After Time Interval
  Amount: 5
  Unit: Seconds / Minutes / Hours / Days
Resume: At Specified Time → {{ $json.retryAt }}
Resume: On Webhook Call   → 외부 시스템이 Webhook 호출 시 재개

## Merge 노드
Mode: Append            → 모든 아이템 단순 합치기
Mode: Merge by Field    → 공통 필드 기준 병합 (SQL LEFT/INNER JOIN)
Mode: Multiplex         → 카르테시안 곱 (모든 조합)
Mode: Choose Branch     → IF True/False 분기 재결합
Mode: Wait for All Inputs → 두 입력 모두 도달 시 진행

## Aggregate 노드
# 여러 아이템을 하나로 집계
Aggregate: All Item Data (Into a List) → [{...}, {...}] → {list: [{...}, {...}]}
Field: items → 특정 필드만 배열로 수집

데이터 변환 노드

## Filter 노드
# 조건에 맞는 아이템만 통과
Condition: {{ $json.score }} Larger than 60
→ 60점 초과 아이템만 다음 노드로

## Sort 노드
Type: Simple
Sort Key: {{ $json.price }}
Order: Ascending / Descending
Type: Random → 무작위 섞기

## Limit 노드
Max Items: 10   → 앞에서 10개만 통과

## Remove Duplicates 노드
Compare: All Fields   → 전체 필드가 같으면 중복
Compare: Selected Fields → 특정 필드 기준 중복 제거
Field: email

## Edit Fields (Set) 노드
Mode: Manual Mapping
  fullName: {{ $json.firstName + ' ' + $json.lastName }}
  timestamp: {{ $now.toISO() }}

Mode: JSON → 전체 json 객체 대체
Include Other Fields: true / false

## Rename Keys 노드
# 필드명 일괄 변경
user_name → userName
created_at → createdAt

유틸리티 노드

## Date & Time 노드
Action: Format a Date
  Value: {{ $json.timestamp }}
  Format: yyyy-MM-dd HH:mm:ss
  Timezone: Asia/Seoul

Action: Add to a Date → {{ $json.date }}.plus({ days: 30 })
Action: Get Current Date → $now

## Crypto 노드
Action: Hash → MD5 / SHA256 / SHA512
  Type: SHA256
  Value: {{ $json.password + $json.salt }}
  Encoding: hex

Action: HMAC → 서명 생성
Action: Generate → UUID, 랜덤 문자열

## HTML Extract 노드
Source Data: {{ $json.html }}
Extraction Values:
  - Key: title
    CSS Selector: h1
    Return Value: Text
  - Key: links
    CSS Selector: a[href]
    Return Value: Attribute (href)
    Return Array: true

## RSS Read 노드
URL: https://feeds.example.com/rss.xml
Limit: 10   → 최신 10개 항목만

실전 워크플로우 예제

예제 1: 날씨 → Slack (기초)

# 매일 9시 서울 날씨 → Slack 전송

## Step 1: Schedule Trigger
Cron: "0 9 * * 1-5"   # 평일 오전 9시
Timezone: Asia/Seoul

## Step 2: HTTP Request (날씨 API)
URL: https://api.open-meteo.com/v1/forecast
Query Parameters:
  latitude: 37.5665
  longitude: 126.9780
  current_weather: true
  timezone: Asia/Seoul

## Step 3: Code (메시지 포맷)
// Code 노드
const w = $input.first().json.current_weather;
const codeMap = {
  0: '맑음 ☀️', 1: '대체로 맑음 🌤️', 2: '흐림 ⛅', 3: '흐림 ☁️',
  45: '안개 🌫️', 61: '비 🌧️', 71: '눈 ❄️', 80: '소나기 🌦️',
  95: '뇌우 ⛈️',
};
const condition = codeMap[w.weathercode] ?? '알 수 없음';
return [{ json: { message:
  `*📅 ${$now.toFormat('yyyy년 MM월 dd일 (cccc)')} 서울 날씨*\n` +
  `날씨: ${condition}\n기온: ${w.temperature}°C\n풍속: ${w.windspeed} km/h`
}}];
## Step 4: Slack
Channel: #daily-weather
Text: {{ $json.message }}
Parse Mode: mrkdwn

예제 2: Webhook API 서버 (중급)

# n8n을 간단한 REST API 서버로 활용

## POST /webhook/users/create → DB 저장 → 이메일 → 응답

Webhook Trigger
  Method: POST
  Path: users/create
  Response Mode: Using 'Respond to Webhook' Node
  ↓

Code 노드 (입력 검증)
  const { name, email, role } = $json.body;
  if (!name || !email) throw new Error('name과 email은 필수입니다');
  if (!email.includes('@')) throw new Error('유효하지 않은 이메일');
  const allowedRoles = ['user', 'admin', 'viewer'];
  if (role && !allowedRoles.includes(role)) throw new Error('허용되지 않은 role');
  return [{ json: { name, email, role: role ?? 'user' } }];
  ↓

PostgreSQL 노드
  Operation: Execute Query
  Query: |
    INSERT INTO users (name, email, role, created_at)
    VALUES ('{{ $json.name }}', '{{ $json.email }}', '{{ $json.role }}', NOW())
    RETURNING id, name, email, role, created_at
  ↓

Gmail 노드 (환영 이메일)
  To: {{ $json.email }}
  Subject: 가입을 환영합니다, {{ $json.name }}님!
  Body: ...
  ↓

Respond to Webhook 노드
  Status Code: 201
  Response Body:
  {
    "success": true,
    "user": {
      "id": {{ $json.id }},
      "name": "{{ $json.name }}",
      "email": "{{ $json.email }}"
    }
  }

UI 가이드

캔버스 조작

단축키동작
Ctrl/Cmd + Enter워크플로우 실행
Ctrl/Cmd + S저장
Ctrl/Cmd + Z / Y실행 취소 / 다시 실행
Ctrl/Cmd + C / V노드 복사 / 붙여넣기
Ctrl/Cmd + D노드 복제
Delete / Backspace선택 노드 삭제
Ctrl/Cmd + A모든 노드 선택
Ctrl/Cmd + Shift + F전체 워크플로우 화면 맞춤
Tab다음 노드로 포커스
더블클릭 (캔버스)노드 추가 메뉴
Space + 드래그캔버스 이동
마우스 스크롤줌 인/아웃
Ctrl/Cmd + 0100% 줌 리셋

디버깅 전략

# 1. 노드 클릭 → Input/Output 탭으로 데이터 확인
# 2. Execute Node → 해당 노드만 단독 실행
# 3. "Pinned Data" — 실행 결과를 고정하여 다운스트림 테스트
#    노드 우클릭 → Pin Data → 이후 실행 시 이 데이터 사용

# 4. Code 노드에서 console.log → "Execution Log" 탭에서 확인
console.log('디버그:', JSON.stringify($json, null, 2));
console.log('아이템 수:', $input.all().length);

# 5. 특정 노드부터 실행 — 노드 우클릭 → "Execute From Here"
# 6. 이전 실행 데이터로 테스트 — Executions → 특정 실행 → "Load"

워크플로우 설정

# 워크플로우 Settings 메뉴
Error Workflow: "에러 알림 워크플로우" 선택
  → 실패 시 해당 워크플로우 자동 실행

Timezone: Asia/Seoul
  → Schedule Trigger, Date 연산의 기준 시각

Caller Policy: Any Workflow
  → 서브워크플로우로 호출 허용 범위

Save Execution Progress: true
  → 각 노드 실행 후 중간 상태 저장 (장애 복구 가능)

Execution Order: v1 (latest)
  → 새 실행 순서 정책 (기본값 유지 권장)

워크플로우 패턴

패턴 1: 동기 Webhook API

Webhook Trigger (Response Mode: Using Respond Node)
  ↓
IF (입력 검증)
  True → 처리 로직 → Respond to Webhook (200)
  False → Respond to Webhook (400, 에러 메시지)

패턴 2: Fan-Out (병렬 처리)

# 하나의 이벤트 → 여러 작업 동시 실행

Webhook Trigger
  ├─→ Slack 알림      (동시 실행)
  ├─→ DB 저장
  ├─→ Email 발송
  └─→ 외부 API 호출
         ↓ (Merge: Append)
      Code (결과 집계)

패턴 3: Fan-In (결과 집계)

# 여러 소스에서 데이터 수집 → 통합

Schedule Trigger
  ├─→ PostgreSQL (매출 데이터)
  ├─→ HTTP (GA4 API)
  └─→ HTTP (Slack 통계)
         ↓ (Merge: Append)
      Code (전체 집계)
         ↓
      Gmail (주간 리포트)

패턴 4: 배치 처리 (대용량)

Schedule Trigger
  ↓
PostgreSQL (미처리 레코드 SELECT)
  ↓
SplitInBatches (50개씩)
  ↓ (각 배치)
  HTTP Request (외부 API)
    ↓
  IF (성공/실패)
    True → PostgreSQL UPDATE (processed = true)
    False → PostgreSQL UPDATE (retry_count + 1)
  ↓ (루프 반복)
IF (noItemsLeft)
  → Slack (완료 알림)

패턴 5: 단계별 파이프라인 (Saga)

# 각 단계가 실패하면 보상(롤백) 트랜잭션 실행

Webhook Trigger (주문 생성)
  ↓
Code (재고 확인)
  ↓ (재고 있음)
HTTP Request (결제 처리)
  ↓ (성공)
PostgreSQL (주문 생성)
  ↓ (성공)
HTTP Request (배송 요청)
  ↓ (실패 시 → Error Workflow)
    → PostgreSQL (주문 취소)
    → HTTP Request (결제 환불)
    → Slack (관리자 알림)
  ↓ (성공)
Gmail (주문 확인 이메일)

패턴 6: 멱등성 보장 (중복 실행 방지)

// Code 노드 — 멱등성 키 기반 중복 처리 방지
const idempotencyKey = $json.eventId || $json.orderId;

// 이미 처리한 이벤트인지 확인 (Redis 또는 DB)
// 다음 노드: Redis GET → IF (존재하면 중단)
return [{ json: { ...($json), idempotencyKey } }];
Webhook Trigger
  ↓
Code (idempotencyKey 추출)
  ↓
Redis (GET idempotencyKey)
  ↓
IF (이미 처리됨)
  True → Respond (409 Conflict)
  False → 처리 로직
            ↓
          Redis (SET idempotencyKey "done" EX 86400)
            ↓
          Respond (200 OK)

다음 단계

📚 n8n 학습 경로
  1. n8n 기초 (현재 페이지) — 설치·개념·표현식·노드·패턴
  2. AI 워크플로우 구축 — Claude/OpenAI 연동, AI Agent, RAG
  3. 고급 활용 — 커스텀 노드, 운영 배포, 보안, 성능
🔗 공식 자료