자동화가 막히는 순간, 노드가 아니라 데이터를 보라
지난 장에서 우리는 RSS를 가져와 AI로 요약하고 Slack으로 보내는 첫 워크플로우를 만들었습니다. 버튼을 눌렀고, 노드가 차례로 초록색으로 바뀌었고, 메시지가 도착했습니다. 그 순간만 보면 n8n은 꽤 단순해 보입니다. 상자를 연결하면 일이 흘러갑니다.
그런데 두 번째 워크플로우부터 이상한 일이 생깁니다. Slack 메시지에는 undefined가 찍히고, Google Sheets에는 빈 행이 들어가며, IF 노드는 분명 참이어야 할 데이터를 거짓으로 보냅니다. HTTP Request 노드는 성공했다고 하는데 다음 노드에서는 필요한 값이 없다고 합니다. 이때 많은 사람이 이렇게 생각합니다.
"내가 n8n 노드를 잘 몰라서 그런가?"
대부분은 아닙니다. 문제는 노드를 모르는 데 있지 않습니다. 데이터가 지금 어떤 모양으로 들어왔고, 어느 노드에서 어떤 이름으로 바뀌었으며, 다음 노드가 그 값을 어떤 경로로 읽고 있는지 보지 못해서 생깁니다.
n8n을 잘한다는 것은 노드를 많이 외우는 것이 아닙니다. 데이터가 어디서 생기고, 어디로 흐르고, 어떤 순간에 모양이 바뀌는지 읽는 능력입니다. 노드는 회사의 부서와 비슷합니다. 마케팅팀, 영업팀, 운영팀, 고객지원팀이 각각 일을 하지만, 회사가 굴러가려면 문서와 요청이 올바른 형식으로 전달되어야 합니다. n8n도 같습니다. 노드는 일을 하고, 데이터는 업무 지시서처럼 이동합니다.
이번 장의 목표는 분명합니다. 워크플로우가 막혔을 때 "왜 안 되지?"라고 멈추지 않고, 스스로 원인을 추적하는 눈을 갖는 것입니다. 이를 위해 노드의 역할, JSON 데이터 구조, 표현식, 디버깅 루틴, 자주 쓰는 핵심 노드를 차례로 익힙니다.

노드는 기능이 아니라 역할로 이해하라
n8n 공식 문서에서는 노드를 워크플로우의 핵심 구성 요소로 설명합니다. 노드는 워크플로우를 시작하거나, 데이터를 가져오고 보내거나, 데이터를 처리하고 조작하는 일을 합니다.1 이 말은 맞지만, 처음 배우는 사람에게는 조금 넓게 느껴집니다. 실전에서는 노드를 이름이 아니라 역할로 나누어 이해하는 편이 훨씬 쉽습니다.
1인 회사의 자동화에서 노드는 크게 여섯 가지 역할로 나눌 수 있습니다.
| 역할 | 하는 일 | 대표 노드 | 쉬운 비유 |
|---|---|---|---|
| Trigger | 워크플로우를 시작한다 | Webhook, Schedule Trigger, Manual Trigger | 출근 버튼, 알람, 초인종 |
| Action | 외부 서비스와 데이터를 주고받는다 | HTTP Request, Gmail, Slack, Google Sheets, Notion | 거래처에 메일 보내기, 장부 기록 |
| Logic | 흐름을 나누고 합치고 제어한다 | IF, Switch, Merge, Wait | 교차로, 신호등, 합류 차선 |
| Data | 데이터를 정리하고 변환한다 | Edit Fields, Aggregate, Sort, Remove Duplicates | 엑셀 정리, 서류 양식 맞추기 |
| Code | 기본 노드로 어려운 예외 처리를 한다 | Code | 사내 개발자에게 짧은 스크립트 부탁하기 |
| AI | LLM이나 에이전트를 호출한다 | OpenAI, Basic LLM Chain, AI Agent | 분석가, 작가, 상담원 역할의 AI 직원 |
여기서 중요한 것은 "한 노드가 하나의 일을 한다"는 감각입니다. 좋은 워크플로우는 한 노드에 너무 많은 책임을 넣지 않습니다. Webhook은 외부 요청을 받는 데 집중하고, Edit Fields는 필요한 필드만 정리하며, IF는 조건을 판단하고, Slack은 알림을 보냅니다. 이렇게 나누면 문제가 생겼을 때 어느 부서에서 문서가 꼬였는지 찾기 쉽습니다.
예를 들어 신규 결제 알림 워크플로우를 생각해 봅시다.
Webhook
↓
Edit Fields
↓
IF
↓
Google Sheets
↓
SlackWebhook은 결제 서비스에서 보낸 원본 데이터를 받습니다. Edit Fields는 그중 고객 이메일, 금액, 상품명, 결제 시간을 보기 좋은 필드로 정리합니다. IF는 금액이 일정 기준 이상인지 판단합니다. Google Sheets는 결제 내역을 기록합니다. Slack은 운영자에게 알림을 보냅니다.
이 흐름에서 Slack 메시지가 비어 있다면 Slack 노드부터 의심할 필요가 없습니다. 먼저 Slack 노드가 받은 입력 데이터를 봐야 합니다. 이미 앞단 Edit Fields에서 customerEmail이라는 필드를 email로 잘못 바꿨을 수도 있고, IF 분기 후 특정 경로에서는 금액 필드가 빠졌을 수도 있습니다. 노드는 대개 시킨 대로 일합니다. 사람이 데이터의 이름과 위치를 착각하는 경우가 훨씬 많습니다.
n8n의 데이터는 '아이템 배열'로 흐른다
n8n을 이해할 때 가장 먼저 넘어야 할 문턱은 JSON입니다. JSON은 데이터를 표현하는 형식입니다. 어렵게 들리지만, 사실상 이름표가 붙은 상자입니다.
{
"name": "Jin",
"email": "[email protected]",
"plan": "pro"
}이 데이터에는 name, email, plan이라는 이름표가 있고, 각각의 값이 들어 있습니다. n8n에서 대부분의 노드는 이런 JSON 데이터를 입력받고, 처리한 뒤, 다시 JSON 형태로 다음 노드에 넘깁니다.
그런데 n8n은 보통 데이터 하나만 다루지 않습니다. 여러 개의 데이터를 한 번에 다룹니다. RSS 글 10개, 신규 가입자 30명, 스프레드시트 행 100개가 한 번의 실행에서 흘러올 수 있습니다. 그래서 n8n의 데이터는 실제로는 "아이템들의 배열"로 흐른다고 이해해야 합니다.
대략 이런 느낌입니다.
[
{
"json": {
"title": "첫 번째 글",
"link": "https://example.com/1"
}
},
{
"json": {
"title": "두 번째 글",
"link": "https://example.com/2"
}
}
]여기서 각 덩어리가 하나의 item입니다. 그리고 각 item 안의 실제 업무 데이터가 json 안에 들어 있습니다. n8n 편집기에서는 이 구조를 조금 더 보기 쉽게 보여주기 때문에 처음에는 배열이라는 느낌이 약할 수 있습니다. 하지만 이 개념을 놓치면 곧바로 혼란이 옵니다.
RSS 노드가 글 10개를 출력하면 다음 AI 노드는 기본적으로 10개의 item을 하나씩 처리합니다. Google Sheets에서 행 50개를 읽어오면 다음 IF 노드는 50번 판단합니다. Slack 노드를 바로 붙이면 메시지가 50개 갈 수도 있습니다. 초보자가 "왜 Slack이 갑자기 폭탄처럼 알림을 보내지?"라고 놀라는 이유가 여기에 있습니다.
n8n에서 데이터 흐름을 볼 때는 항상 세 가지를 확인해야 합니다.
지금 몇 개의 item이 흐르고 있는가?
각 item 안의 JSON에는 어떤 필드가 있는가?
다음 노드는 그 필드를 어떤 이름과 경로로 읽고 있는가?
이 세 질문만 습관이 되어도 디버깅 속도가 크게 빨라집니다.
필드 경로를 읽는 법: 점 하나가 자동화를 살린다
JSON에서 원하는 값을 꺼내려면 경로를 알아야 합니다. 경로란 "상자 안의 상자 안의 어떤 이름표를 찾아갈 것인가"입니다.
예를 들어 Webhook이 이런 데이터를 받았다고 해봅시다.
{
"body": {
"user": {
"name": "Jin",
"email": "[email protected]"
},
"order": {
"id": "ORD-1001",
"amount": 49000
}
}
}현재 item의 JSON에서 이메일을 꺼내려면 다음과 같이 씁니다.
{{ $json.body.user.email }}주문 금액은 이렇게 꺼냅니다.
{{ $json.body.order.amount }}여기서 $json은 "현재 item의 JSON 데이터"를 뜻합니다. n8n 표현식에서 가장 자주 쓰는 변수입니다. 공식 문서도 이전 노드의 값을 가져오거나, 가벼운 계산과 변환을 할 때 표현식을 사용한다고 설명합니다.2
배열이 들어 있으면 대괄호로 순서를 지정합니다.
{
"items": [
{ "name": "Basic Plan", "price": 19000 },
{ "name": "Pro Plan", "price": 49000 }
]
}첫 번째 상품 이름은 이렇게 읽습니다.
{{ $json.items[0].name }}두 번째 상품 가격은 이렇게 읽습니다.
{{ $json.items[1].price }}프로그래밍 세계에서는 배열의 첫 번째 순서가 1이 아니라 0입니다. 처음에는 낯설지만, n8n에서 API 응답을 다루다 보면 자주 만납니다.
필드 이름에 공백이나 하이픈이 있으면 점 표기법이 깨질 수 있습니다. 이때는 대괄호 표기법을 씁니다.
{
"first-name": "Jin",
"Order ID": "ORD-1001"
}{{ $json["first-name"] }}
{{ $json["Order ID"] }}표현식 오류의 상당수는 복잡한 문제가 아닙니다. body.email인 줄 알았는데 실제로는 body.user.email이거나, customer_email인 줄 알았는데 customerEmail이거나, 배열의 첫 번째 값을 꺼내야 하는데 배열 전체를 그대로 넘긴 경우입니다. 자동화는 대문자 하나, 밑줄 하나에도 민감합니다. 그래서 추측하지 말고 출력 데이터를 직접 봐야 합니다.
표현식은 작은 배관이다
n8n의 표현식은 노드 설정값 안에서 동적으로 데이터를 끌어오는 문법입니다. 입력창에 고정된 텍스트를 쓰는 대신, 실행 시점의 데이터를 넣고 싶을 때 사용합니다. 중괄호 두 겹 안에 값을 가져오는 코드를 넣습니다.
{{ $json.email }}이 표현식은 현재 item의 email 값을 가져옵니다. Gmail 노드의 수신자 필드에 넣으면 매 item마다 다른 이메일 주소로 메일을 보낼 수 있습니다. Slack 메시지 본문에 넣으면 실행할 때마다 다른 고객 이름이나 주문 금액이 들어갑니다.
예를 들어 신규 가입자에게 보내는 환영 메시지를 만든다면 이렇게 쓸 수 있습니다.
안녕하세요, {{ $json.name }}님!
{{ $json.plan }} 플랜 가입을 환영합니다.조금 더 실전적으로는 기본값을 넣을 수도 있습니다.
{{ $json.company ?? "회사명 없음" }}??는 왼쪽 값이 없을 때 오른쪽 값을 대신 쓰라는 뜻입니다. 외부 폼이나 API에서 데이터가 항상 깔끔하게 들어오지는 않기 때문에 이런 기본값 처리는 매우 유용합니다.
문자열을 조합할 때는 템플릿 리터럴을 쓰면 읽기 쉽습니다.
{{ `신규 결제: ${$json.email} / ${$json.amount}원` }}날짜를 넣을 때는 $now를 쓸 수 있습니다.
{{ $now.toISODate() }}다만 표현식은 "작은 배관"입니다. 하나의 값을 꺼내거나, 짧게 가공하거나, 메시지 문장을 만드는 데 적합합니다. 배열 전체를 재구성하거나, 여러 조건을 복잡하게 계산하거나, 반복문을 돌려야 한다면 Code 노드가 더 낫습니다. n8n 문서도 표현식, Code 노드, 데이터 변환 노드를 상황에 따라 구분해 사용하라고 안내합니다.2
실전 기준은 단순합니다. 한 줄로 읽히면 표현식, 읽다가 눈살이 찌푸려지면 Code 노드입니다.
이전 노드의 데이터를 다시 꺼내 쓰기
워크플로우가 길어지면 바로 앞 노드의 데이터만으로는 부족할 때가 있습니다. 예를 들어 Webhook에서 받은 원본 고객 이메일을 중간에 AI 분석, DB 조회, 조건 분기까지 거친 뒤 마지막 Slack 메시지에서 다시 쓰고 싶을 수 있습니다.
이때 모든 노드가 이메일 필드를 계속 넘기게 만들 수도 있지만, 특정 노드의 출력을 직접 참조하는 방법도 있습니다.
최근 n8n 표현식에서는 보통 다음과 같은 방식으로 특정 노드 데이터를 가져올 수 있습니다.
{{ $('Webhook').item.json.body.email }}또는 환경과 버전에 따라 다음 형태를 보게 될 수도 있습니다.
{{ $node["Webhook"].json.body.email }}핵심은 노드 이름입니다. Webhook이라고 썼다면 실제 캔버스의 노드 이름도 정확히 Webhook이어야 합니다. 노드 이름을 결제 Webhook으로 바꾸었다면 표현식도 그 이름에 맞춰야 합니다.
이 사실은 유지보수와도 연결됩니다. 노드 이름을 대충 HTTP Request1, HTTP Request2, Set3처럼 놔두면 나중에 표현식이 지저분해집니다.
{{ $('HTTP Request3').item.json.data.customer.email }}이 표현식은 읽는 순간 불안합니다. HTTP Request3가 무엇을 하는 노드인지 알 수 없기 때문입니다. 반면 노드 이름을 바꾸면 훨씬 좋아집니다.
{{ $('결제 정보 조회').item.json.data.customer.email }}표현식은 단순한 문법이 아니라 워크플로우의 가독성과 연결됩니다. 이름을 잘 지은 노드는 나중의 나에게 보내는 친절한 안내문입니다.
데이터가 바뀌는 순간을 잡는 디버깅 루틴
워크플로우가 실패했을 때 초보자는 흔히 마지막 노드만 들여다봅니다. Slack 메시지가 이상하면 Slack 노드 설정을 만지고, Gmail 발송이 실패하면 Gmail 노드만 다시 봅니다. 하지만 데이터 문제는 보통 그보다 앞에서 시작됩니다.
디버깅은 범인을 찾는 일이 아니라, 데이터가 바뀐 순간을 찾는 일입니다. n8n 편집기에서는 각 노드의 입력과 출력을 확인할 수 있고, 실행 기록에서 과거 실행의 데이터도 볼 수 있습니다. 제공 자료에서 강조하듯 n8n 디버깅의 핵심은 노드 사이를 이동하는 JSON을 단계별로 관찰하는 것입니다.3
실전에서는 다음 순서로 움직이면 됩니다.
실패한 노드를 클릭해 에러 메시지를 읽는다.
그 노드의 입력 데이터가 기대한 모양인지 확인한다.
바로 앞 노드의 출력 데이터와 비교한다.
필드명이 바뀌었는지, 값이 비었는지, item 개수가 달라졌는지 확인한다.
표현식 미리보기에서 실제 값이 어떻게 해석되는지 본다.
필요한 경우 Pin data로 테스트 데이터를 고정하고 같은 조건을 반복한다.
Execute previous nodes로 앞단 데이터 생성 과정을 다시 실행해 재현한다.
이 루틴이 몸에 붙으면 "어디가 문제인지 모르겠다"는 시간이 크게 줄어듭니다.
예를 들어 Slack 메시지에 undefined가 찍혔다고 해봅시다. 메시지 본문에는 이렇게 써 있습니다.
신규 가입자: {{ $json.email }}그런데 Slack 노드의 입력 데이터를 보니 실제 구조가 이렇습니다.
{
"user": {
"email": "[email protected]"
}
}그렇다면 문제는 Slack이 아닙니다. 표현식 경로가 틀렸습니다.
신규 가입자: {{ $json.user.email }}이번에는 Google Sheets에 빈 행이 들어간다고 해봅시다. Google Sheets 노드 입력을 보니 name, email, createdAt 필드가 있어야 하는데 email이 없습니다. 앞 노드로 올라가 보니 Edit Fields에서 emailAddress라는 이름으로 바꿔 놓았습니다. 이때 해결책은 둘 중 하나입니다. Google Sheets 노드가 emailAddress를 읽게 하거나, Edit Fields에서 필드명을 다시 email로 맞춥니다.
대부분의 디버깅은 이런 식입니다. 복잡한 마법이 아니라, 영수증을 거슬러 올라가는 일에 가깝습니다.
Pin data: 흔들리는 테스트 데이터를 책상 위에 고정하기
외부 API, Webhook, 이메일 트리거, RSS 피드처럼 바깥세상에서 들어오는 데이터는 매번 달라질 수 있습니다. 방금 전에는 결제 데이터가 있었는데, 다시 실행하니 새 이벤트가 없어서 빈 값이 올 수 있습니다. 디버깅 중에는 이런 변동성이 방해가 됩니다.
이때 Pin data가 유용합니다. Pin data는 특정 노드의 출력 데이터를 테스트용으로 고정해 두는 기능입니다. 한 번 받은 샘플 데이터를 책상 위에 붙여 놓고, 뒤쪽 노드를 반복해서 고칠 수 있게 해줍니다.
예를 들어 Webhook으로 결제 데이터를 받는 워크플로우를 만들고 있다고 합시다. 결제 서비스에서 실제 테스트 결제를 매번 발생시키는 것은 번거롭습니다. 한 번 정상적인 Webhook 데이터를 받은 뒤 그 출력을 Pin data로 고정하면, 이후에는 Edit Fields, IF, Slack, Google Sheets 노드를 여러 번 수정하며 테스트할 수 있습니다.
Pin data를 쓸 때의 감각은 이렇습니다.
외부 세계를 다시 부르지 않고,
이미 받은 샘플 데이터로 뒤쪽 파이프를 고친다.다만 주의할 점도 있습니다. Pin data는 테스트를 편하게 해주지만, 실제 운영 데이터를 완전히 대체하지는 않습니다. 고정된 샘플 하나로는 다양한 예외를 모두 확인할 수 없습니다. 이메일이 없는 고객, 금액이 0인 결제, 상품 배열이 비어 있는 주문, 첨부파일이 없는 CS 문의 같은 데이터도 따로 테스트해야 합니다.
Pin data는 디버깅의 망치이지, 품질 보증 전체가 아닙니다.
Execute previous nodes: 앞단을 다시 재현하기
노드를 하나씩 테스트하다 보면 이런 상황이 생깁니다. 지금 고치고 싶은 노드는 중간에 있는데, 그 노드가 실행되려면 앞의 Webhook, HTTP Request, Edit Fields가 먼저 데이터를 만들어야 합니다. 이때 앞 노드들을 매번 수동으로 하나씩 실행하는 것은 번거롭습니다.
Execute previous nodes는 현재 노드 앞에 있는 노드들을 실행해 입력 데이터를 다시 생성하는 데 도움을 줍니다. 말하자면 "이 노드가 일하려면 필요한 재료를 앞 부서에서 다시 만들어 와"라고 요청하는 기능입니다.
이 기능은 특히 다음 상황에서 유용합니다.
앞단 API 응답이 바뀌었는지 확인하고 싶을 때
Edit Fields 설정을 바꾼 뒤 다음 노드 입력이 제대로 바뀌었는지 보고 싶을 때
IF나 Switch 조건이 실제 데이터에서 어떤 경로로 흐르는지 다시 확인하고 싶을 때
AI 노드의 출력 형식이 바뀐 뒤 후속 노드가 여전히 작동하는지 확인하고 싶을 때
디버깅을 잘하는 사람은 전체 워크플로우를 무작정 반복 실행하지 않습니다. 필요한 구간만 재현합니다. 그래야 API 호출 비용도 줄고, Slack 알림 폭탄도 피하고, 원인도 더 빨리 좁힐 수 있습니다.
자주 만나는 오류는 대개 세 가지다
n8n에서 초보자가 만나는 데이터 오류는 다양해 보이지만, 뿌리는 대체로 세 가지입니다.
첫째, 필드명이 다릅니다. email이라고 생각했는데 실제로는 customer_email입니다. title이라고 생각했는데 RSS 노드에서는 contentSnippet에 핵심 내용이 들어 있습니다. API 버전이 바뀌면서 data.user.name이 data.customer.name으로 바뀌기도 합니다.
둘째, 값이 비어 있습니다. 폼 제출자가 전화번호를 입력하지 않았거나, AI가 기대한 형식으로 답하지 않았거나, Google Sheets 조회 결과가 0건일 수 있습니다. 이 경우 표현식은 틀리지 않았지만 읽을 값이 없습니다.
셋째, item 개수가 예상과 다릅니다. 하나만 온다고 생각했는데 10개가 오거나, 여러 개가 올 줄 알았는데 하나로 합쳐져 있습니다. Merge, Aggregate, Split Out, Google Sheets 조회 노드 주변에서 자주 생깁니다.
이 세 가지를 확인하는 질문은 간단합니다.
이름이 맞나?
값이 있나?
개수가 맞나?정말 많은 문제가 이 세 질문 안에서 해결됩니다. 이 질문을 습관처럼 던지면, n8n은 훨씬 덜 무섭습니다.
솔로프리너가 자주 쓰는 12개 노드
n8n에는 수많은 노드가 있습니다. 하지만 1인 회사의 자동화에서 처음부터 수백 개를 알 필요는 없습니다. 대부분의 실전 워크플로우는 몇 개의 핵심 노드를 조합해 시작합니다. 아래 12개만 익혀도 콘텐츠, 마케팅, CS, 제품 운영, 인프라 알림의 상당 부분을 만들 수 있습니다.
| 노드 | 역할 | 솔로프리너 활용 예 |
|---|---|---|
| Webhook | 외부 요청을 받아 워크플로우 시작 | 결제 완료, 폼 제출, SaaS 이벤트 수신 |
| Schedule Trigger | 정해진 시간에 실행 | 매일 리포트, 주간 콘텐츠 수집, 비용 점검 |
| HTTP Request | 외부 API 호출 | 지원하지 않는 SaaS API 연결, 내부 서비스 호출 |
| Edit Fields | 필드 추가·삭제·이름 변경 | API 응답을 내가 쓰는 표준 필드명으로 정리 |
| Code | 복잡한 변환과 예외 처리 | 배열 재구성, 커스텀 점수 계산, 데이터 정규화 |
| IF | 참/거짓 조건 분기 | VIP 고객 여부, 금액 기준, 필수 값 존재 여부 판단 |
| Switch | 여러 경로로 분기 | 문의 유형별 담당자 배정, 결제 플랜별 처리 |
| Merge | 여러 흐름 병합 | 고객 정보와 결제 정보를 합쳐 Slack 알림 생성 |
| Google Sheets | 간단한 기록과 조회 | 리드 목록, 결제 로그, 콘텐츠 캘린더 관리 |
| Notion | 문서와 데이터베이스 관리 | 콘텐츠 아이디어, CS 티켓, 프로젝트 보드 생성 |
| Gmail | 이메일 발송과 수신 처리 | 온보딩 메일, 결제 안내, 문의 자동 분류 |
| Slack | 알림과 운영 커뮤니케이션 | 결제 알림, 장애 알림, 일일 요약 리포트 |
이 목록에서 특히 중요한 노드는 HTTP Request입니다. n8n에 특정 서비스 전용 노드가 없더라도, 그 서비스가 API를 제공한다면 HTTP Request로 연결할 수 있습니다. 처음에는 어렵게 느껴지지만, 장기적으로는 n8n의 확장성을 여는 만능 어댑터입니다.
반대로 Edit Fields는 과소평가되기 쉽습니다. 하지만 실무에서는 이 노드가 워크플로우의 정리 담당자 역할을 합니다. 외부 API마다 제각각인 필드명을 내 회사의 표준 필드명으로 맞추는 순간, 뒤쪽 노드들이 훨씬 단순해집니다.
예를 들어 어떤 결제 API는 고객 이메일을 customer_email로 주고, 다른 서비스는 customer.email로 줄 수 있습니다. Edit Fields에서 모두 email로 통일하면, 뒤쪽 Gmail, Slack, Google Sheets 노드는 언제나 $json.email만 읽으면 됩니다.
{
"email": "[email protected]",
"amount": 49000,
"plan": "pro",
"paidAt": "2026-05-06T09:00:00+09:00"
}이렇게 표준 형태를 만드는 습관은 워크플로우가 길어질수록 큰 차이를 만듭니다.
Logic 노드는 자동화의 교차로다
초보자는 처음에 Action 노드에 끌립니다. Gmail 보내기, Slack 알림 보내기, Notion 페이지 만들기처럼 결과가 눈에 보이기 때문입니다. 하지만 자동화가 진짜 회사 시스템처럼 작동하려면 Logic 노드가 필요합니다.
IF는 가장 단순한 교차로입니다. 조건이 맞으면 위쪽 길, 아니면 아래쪽 길로 보냅니다.
결제 금액이 100,000원 이상인가?
├─ true → VIP 알림
└─ false → 일반 기록Switch는 갈림길이 여러 개인 교차로입니다.
문의 유형은 무엇인가?
├─ billing → 결제 문의 처리
├─ bug → 버그 리포트 생성
├─ feature → 기능 요청 DB 저장
└─ other → 일반 문의 큐로 이동Merge는 갈라졌던 길을 다시 합치는 노드입니다. 예를 들어 한쪽에서는 결제 정보를 가져오고, 다른 쪽에서는 고객 프로필을 가져온 뒤, 두 데이터를 합쳐 Slack 메시지를 만들 수 있습니다.
Logic 노드를 잘 쓰면 자동화는 단순 반복을 넘어 판단을 하기 시작합니다. 물론 이 판단은 인간처럼 생각한다는 뜻이 아닙니다. 명확한 기준에 따라 흐름을 다르게 보낸다는 뜻입니다. 그리고 이 기준 위에 AI 노드를 얹으면, 나중에는 문의 의도 분류나 콘텐츠 품질 평가처럼 더 유연한 자동화도 가능해집니다.
Code 노드는 최후의 카드이지 첫 번째 카드가 아니다
n8n은 로우코드 도구입니다. 필요할 때 JavaScript나 Python을 쓸 수 있다는 점이 큰 장점입니다. 하지만 모든 문제를 Code 노드로 해결하려고 하면 n8n의 장점이 사라집니다.
Code 노드는 다음과 같은 상황에서 빛납니다.
여러 item을 새로운 구조로 재구성해야 할 때
복잡한 조건문이나 계산이 필요할 때
표현식으로 쓰면 너무 길고 읽기 어려울 때
배열을 펼치거나 묶거나 점수를 계산해야 할 때
예외 상황을 세밀하게 처리해야 할 때
예를 들어 주문 목록에서 총액을 계산하는 간단한 코드는 다음처럼 작성할 수 있습니다.
const items = $input.all();
return items.map(item => {
const quantity = item.json.quantity ?? 0;
const unitPrice = item.json.unitPrice ?? 0;
return {
json: {
...item.json,
totalPrice: quantity * unitPrice,
},
};
});여기서 중요한 것은 반환 형태입니다. Code 노드는 다음 노드가 이해할 수 있도록 item 배열을 반환해야 합니다. 각 item 안에는 보통 json 객체가 들어갑니다. 이 구조를 무시하면 다음 노드에서 데이터를 제대로 읽지 못합니다.
하지만 단순히 이메일을 소문자로 바꾸는 정도라면 Code 노드까지 갈 필요가 없습니다.
{{ $json.email?.toLowerCase().trim() }}이 한 줄이면 충분합니다. 자동화 설계에서는 "할 수 있다"보다 "유지보수하기 쉽다"가 더 중요합니다. 나중에 다시 봤을 때 이해할 수 있는 쪽을 선택하세요.
AI 노드는 똑똑하지만 데이터 계약이 필요하다
앞으로 우리는 AI Agent, RAG, MCP, 멀티 에이전트까지 다룰 것입니다. 하지만 AI 노드도 결국 n8n 안에서는 하나의 노드입니다. 입력을 받고, LLM을 호출하고, 출력을 다음 노드로 넘깁니다.
AI 노드에서 초보자가 자주 겪는 문제는 "AI가 말을 너무 자유롭게 한다"는 것입니다. 사람에게는 자연스러운 답변이지만, 다음 노드에게는 애매한 데이터가 됩니다.
예를 들어 CS 문의를 AI가 분류하게 했다고 합시다. 프롬프트에 "문의 유형을 분류해줘"라고만 쓰면 AI는 이렇게 답할 수 있습니다.
이 문의는 결제 관련 문제로 보입니다. 사용자가 환불 가능 여부를 묻고 있습니다.사람이 읽기에는 좋지만 Switch 노드가 쓰기에는 불편합니다. Switch는 billing, bug, feature, other 같은 명확한 값이 필요합니다.
그래서 AI 노드를 쓸 때는 출력 형식을 최대한 분명하게 요구해야 합니다.
다음 문의를 분류하세요.
반드시 아래 네 값 중 하나만 출력하세요.
billing
bug
feature
other
문의: {{ $json.message }}더 엄격한 구조가 필요하면 뒤쪽 장에서 Output Parser나 JSON Schema를 사용합니다. 지금 단계에서 기억할 것은 하나입니다. AI도 다음 노드와 데이터 계약을 맺어야 합니다. "무슨 값이 어떤 필드명으로 나올지"가 정해져야 자동화가 안정됩니다.
유지보수 가능한 워크플로우는 이름에서 시작된다
처음 만든 워크플로우는 보통 짧습니다. 노드가 4개뿐이라 이름이 엉망이어도 큰 문제가 없습니다. 하지만 자동화가 실제 사업에 들어오면 노드는 금방 늘어납니다. 콘텐츠 발행 워크플로우 하나에도 수집, 중복 확인, AI 초안, 검수 요청, 게시 예약, Slack 알림, 기록 저장이 들어갑니다.
그때부터는 작동하는 워크플로우보다 이해 가능한 워크플로우가 더 중요합니다. 자동화는 한 번 만들고 끝나는 물건이 아닙니다. 상품이 바뀌고, API가 바뀌고, 고객 응대 방식이 바뀌고, AI 모델이 바뀌면 계속 수정됩니다.
노드 이름은 "무엇을 하는지"가 드러나야 합니다.
| 나쁜 이름 | 좋은 이름 |
|---|---|
| HTTP Request | 결제 API에서 주문 상세 조회 |
| Set | Slack 알림용 필드 정리 |
| IF | 결제 금액 10만원 이상 여부 확인 |
| Code | 리뷰 점수와 우선순위 계산 |
| Google Sheets | 결제 로그 시트에 행 추가 |
좋은 이름은 길어도 괜찮습니다. 캔버스에서 노드 이름은 문서 역할을 합니다. 특히 표현식에서 특정 노드를 참조할 때 이름이 명확하면 실수를 줄일 수 있습니다.
긴 워크플로우는 기능 단위로 묶어 배치하세요. 왼쪽에서 오른쪽으로 흐르게 두되, 비슷한 기능은 가까이 둡니다. 예를 들어 다음처럼 구역을 나눌 수 있습니다.
[입력 수신]
Webhook → 입력 검증
[데이터 정리]
Edit Fields → Code
[판단]
IF → Switch
[실행]
Gmail → Slack → Google Sheets
[에러/기록]
실패 알림 → 실행 로그 저장n8n에는 노드 메모를 남길 수 있는 설정도 있습니다. 공식 문서에서도 노드 설정에서 동작 제어와 노트 추가가 가능하다고 안내합니다.1 복잡한 조건을 만들었다면 "왜 이 조건이 필요한지"를 적어 두세요. 지금의 나는 기억하지만, 3개월 뒤의 나는 모릅니다. 자동화는 미래의 나와 협업하는 일입니다.
필드명은 회사의 언어다
워크플로우가 많아질수록 필드명 일관성이 중요해집니다. 어떤 워크플로우에서는 email, 다른 워크플로우에서는 customerEmail, 또 다른 곳에서는 customer_email을 쓰면 나중에 연결할 때마다 헷갈립니다.
1인 회사라도 내부 표준 필드명을 정하는 것이 좋습니다. 예를 들어 고객 관련 데이터는 다음처럼 정할 수 있습니다.
| 의미 | 추천 필드명 |
|---|---|
| 고객 이메일 | email |
| 고객 이름 | name |
| 가입 플랜 | plan |
| 결제 금액 | amount |
| 결제 시각 | paidAt |
| 문의 내용 | message |
| 문의 유형 | category |
| 우선순위 | priority |
외부 서비스가 어떤 이름으로 데이터를 주든, 워크플로우 초반에 Edit Fields나 Code 노드로 내부 표준에 맞춥니다. 이렇게 하면 뒤쪽 노드들은 항상 같은 언어를 씁니다. 자동화가 많아질수록 이 작은 규칙이 시스템 전체의 안정성을 만듭니다.
작은 실습: 필드명을 일부러 고쳐 보라
이 장을 읽고 바로 해볼 만한 연습이 있습니다. 지난 장에서 만든 RSS → AI 요약 → Slack 워크플로우를 열어 보세요. 그리고 RSS 노드 다음에 Edit Fields 노드를 하나 넣습니다.
RSS 원본에서 필요한 값을 다음 이름으로 정리합니다.
{
"articleTitle": "원본 title 값",
"articleUrl": "원본 link 값",
"articleText": "원본 content 또는 description 값"
}그다음 AI 노드의 프롬프트를 바꿉니다.
제목: {{ $json.articleTitle }}
본문: {{ $json.articleText }}
링크: {{ $json.articleUrl }}이 실습의 목적은 단순합니다. 외부 데이터의 필드명을 그대로 끌고 다니지 않고, 내가 이해하기 쉬운 이름으로 바꾸는 감각을 익히는 것입니다.
이후 Slack 노드에서 원문 링크를 넣을 때도 다음처럼 씁니다.
원문: {{ $json.articleUrl }}만약 Slack 메시지에서 링크가 비어 있다면 디버깅 루틴을 적용합니다. Slack 노드 입력에 articleUrl이 있는지 봅니다. 없다면 AI 노드가 그 필드를 없앴는지 봅니다. AI 노드가 입력은 받았지만 출력에서 원본 필드를 넘기지 않았다면, AI 노드 뒤에 다시 원본 노드를 참조하거나, Merge로 원본 데이터와 AI 결과를 합치는 구조를 고민해야 합니다.
이 작은 실습 안에 n8n의 핵심이 들어 있습니다. 필드명을 정하고, 데이터가 사라진 지점을 찾고, 필요한 데이터를 다시 이어 붙이는 능력입니다.
지금 기억해야 할 것
이번 장에서 배운 내용은 화려하지 않습니다. 하지만 앞으로 만들 모든 자동화의 바닥입니다. n8n에서 노드는 상자처럼 보이지만, 실제로는 데이터가 이동하는 파이프입니다. Trigger가 흐름을 시작하고, Action이 외부 서비스와 일하며, Logic이 길을 나누고, Data 노드가 모양을 정리하고, Code가 예외를 처리하고, AI가 지능적인 판단과 생성을 맡습니다.
워크플로우가 막힐 때는 노드 이름을 검색하기 전에 데이터를 보세요. 현재 item이 몇 개인지, JSON 안에 어떤 필드가 있는지, 표현식이 실제로 어떤 값을 읽고 있는지 확인하세요. Pin data로 테스트 데이터를 고정하고, Execute previous nodes로 앞단을 재현하며, 입력과 출력을 비교하세요.
n8n을 잘한다는 것은 모든 노드를 외우는 것이 아닙니다. 데이터가 어디서 어떻게 바뀌는지 읽는 것입니다. 그 눈이 생기면 자동화는 더 이상 우연히 작동하는 장난감이 아닙니다. 혼자 일하는 사람의 회사 안에서 반복 가능한 시스템이 됩니다.
다음 장부터는 이 데이터 흐름 감각을 바탕으로 실제 사업 영역에 들어갑니다. 먼저 콘텐츠 자동화입니다. 블로그 글 하나를 여러 채널로 바꾸고, 영상에서 글을 만들고, 검색 트렌드에서 주제를 뽑아내는 흐름을 설계합니다. 이제 노드 하나하나가 아니라, 1인 회사의 생산 라인을 만들 차례입니다.
참고
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.