n8n 개발자 편: 구조, 기능, 그리고 백엔드로 쓰기

이 글은 시리즈 2편이다. “n8n이 뭐고 나한테 필요한가” 는 비개발자 편에서 다뤘다. 여기서는 설치·구조·기능·운영을 다룬다.

n8n 워크플로를 4개월간 72개 만들었다. 그중 20여 개가 지금도 1~5분 주기로 돌고 8개 부서가 쓴다. 손으로 하던 기준으로 월 37시간쯤 줄었다.

그 과정에서 생각이 한 번 바뀌었다. 처음엔 “서비스끼리 연결하는 도구”로 봤는데, 지금은 백엔드로 쓴다. 서버도 DB 도 안 만들고 사내 앱 하나를 통째로 올린 적도 있다.

기능 카탈로그를 나열하는 글은 이미 많으니, 각 기능마다 언제 쓰고 언제 안 쓰는지를 붙인다. 마지막 절반은 실전 딥다이브다 — 백엔드로 쓸 때의 구조, 20개가 넘어가면서 겪은 것들, 그리고 쓰면 안 되는 곳.

n8n 이 뭔가

서로 다른 서비스를 연결해 “이 일이 생기면 저 일을 한다”를 만드는 도구다. 화면에서 노드를 선으로 잇고, 필요하면 중간에 JavaScript 나 Python 을 끼워 넣는다.

위치는 이렇다.

직접 코드n8nZapier 류 SaaS
자유도높음중간~높음낮음
유지보수전부 내가화면에서 확인거의 없음
실행 건수 비용서버 비용만자체 호스팅이면 서버 비용만건당 과금
데이터 위치내 서버자체 호스팅이면 내 서버외부

자체 호스팅에서 실행 건수 과금이 없다는 게 실질적인 차이다. 1분 주기로 도는 워크플로를 건당 과금으로 굴리면 금액이 금방 올라간다.

라이선스부터 짚고 간다

n8n 은 오픈소스가 아니다. 한국어 소개 글 상당수가 오픈소스라고 쓰는데 정확하지 않다.

2022년 3월에 Apache-2.0 + Commons Clause 에서 Sustainable Use License 로 바꿨다. fair-code 라 부르는 방식이고 OSI 인증 라이선스가 아니다. 실무에 걸리는 건 한 줄이다.

내부 업무 목적, 비영리, 개인 용도로만 자유롭게 쓸 수 있다.

  • 우리 회사 업무를 자동화한다 → 무료
  • 클라이언트 업무를 대신 자동화해준다 → 대체로 문제 없음
  • n8n 을 호스팅해서 남에게 서비스로 판다 → 상용 라이선스 필요

대부분은 앞의 둘이라 그냥 쓰면 된다. 다만 “n8n 기반 자동화 SaaS” 를 구상 중이라면 여기서 멈춰야 한다. 제품을 다 만든 다음에 아는 게 제일 비싸다.

기본 구조: 트리거 · 노드 · 아이템

문서를 처음부터 읽을 필요 없다. 이 셋이 전부다.

트리거 — 워크플로가 언제 시작되는지. 앱 이벤트, 스케줄(cron), 웹훅, 챗 인터페이스가 있다. 워크플로 하나에 트리거는 하나다.

노드 — 하나의 동작. 400개가 넘는 서비스별 전용 노드가 있고, 없으면 HTTP Request 노드로 아무 API 나 부른다. curl 명령을 그대로 붙여넣어 노드로 바꾸는 기능도 있다.

아이템 — 노드 사이를 흐르는 데이터. 여기가 처음에 제일 많이 막힌다. n8n 은 아이템을 배열로 다룬다. 앞 노드가 10개를 내보내면 다음 노드는 10번 실행된다. 이걸 모르면 “왜 알림이 10번 왔지”가 된다.

세 번째만 제대로 잡으면 나머지는 화면 보면서 익힌다.

알아두면 바로 쓰는 기능들

여기부터가 실제로 도움이 되는 부분이다.

데이터 변형 노드

Merge, Loop, Filter, Remove Duplicates, Split Out, Aggregate 가 기본 제공된다. API 응답을 가공하려고 Code 노드부터 여는 습관이 제일 흔한 낭비다. 중복 제거나 배열 펼치기는 전용 노드가 이미 있고, 그쪽이 화면에서 읽힌다.

Code 노드

JavaScript 와 Python 둘 다 쓸 수 있다. 자체 호스팅이면 npm 패키지도 불러올 수 있다. 전용 노드로 안 되는 변형이 있을 때만 여는 게 맞다.

표현식(Expressions)

파라미터에 {{ }} 로 값을 끼워 넣는다. 앞 노드 결과를 참조하거나 날짜를 계산할 때 쓴다. 노드 하나 추가할 걸 표현식 한 줄로 끝내는 경우가 많다.

오류 처리 — 여기가 핵심이다

자동화는 성공할 때가 아니라 조용히 실패할 때 아프다. n8n 은 두 층위로 나눠 다룬다.

노드 단위 설정 (노드 Settings 탭)

설정동작
Retry On Fail실패하면 성공할 때까지 재실행
On Error → Stop Workflow워크플로 전체 중단 (기본)
On Error → Continue오류를 무시하고 직전 유효 데이터로 진행
On Error → Continue (using error output)오류 정보를 별도 출력선으로 흘려보냄
Always Output Data결과가 없어도 빈 아이템을 내보냄
Execute Once아이템이 여러 개여도 첫 번째로 한 번만 실행

Continue (using error output) 가 특히 쓸모 있다. 성공 흐름과 실패 흐름을 화면에서 갈라 놓을 수 있어서, 실패했을 때만 알림을 보내는 분기를 따로 만들 수 있다.

워크플로 단위 설정 — Workflow Settings 의 Error workflow

실행이 실패하면 지정한 다른 워크플로가 대신 실행된다. 그 워크플로는 Error Trigger 노드로 시작해야 한다. Error Trigger 는 이런 데이터를 받는다.

{
  "execution": {
    "id": "231",
    "url": "https://n8n.example.com/execution/231",
    "error": { "message": "Example Error Message", "stack": "Stacktrace" },
    "lastNodeExecuted": "Node With Error"
  },
  "workflow": { "id": "1", "name": "Example Workflow" }
}

lastNodeExecutedurl 이 들어 있어서, 알림에 “어느 워크플로의 어느 노드에서 터졌고 여기 링크” 까지 담을 수 있다. 에러 워크플로 하나를 만들어 전체 워크플로에 같은 걸 지정하면 된다. 20개가 넘어가면 이게 없으면 감당이 안 된다.

한 가지 주의. 트리거 노드 자체에서 실패하면 execution.idurl 이 안 들어온다. 실행이 시작되지도 않아서다. 알림 문구를 만들 때 이 필드가 없는 경우를 고려해야 한다.

서브 워크플로

워크플로가 다른 워크플로를 호출한다. 메신저 발송이나 알림 라우팅처럼 반복되는 조각을 별도 워크플로로 빼두면 채널이 바뀔 때 한 곳만 고치면 된다. 이름에 lib_ 같은 접두어를 붙여 두면 목록에서 구분된다.

AI 노드

LLM 을 노드로 붙일 수 있고, AI Agent 노드는 도구(tool)를 여러 개 물려주면 에이전트가 알아서 뭘 호출할지 정한다. 문서 요약처럼 규칙으로 못 짜는 판단을 끼워 넣을 때 쓴다.

실무에서 쓸 만한 조합은 기계 규칙으로 먼저 거르고 애매한 것만 LLM 에 넘기는 방식이다. 전부 LLM 에 태우면 비용도 지연도 올라가고, 규칙으로 확실히 판정되는 걸 굳이 확률에 맡기게 된다.

실행 이력과 디버깅

실행마다 각 노드의 입출력이 남아서 어디서 틀어졌는지 화면에서 본다. 이전 실행 데이터를 현재 워크플로로 불러와 재현할 수도 있어서, 외부 이벤트를 다시 발생시키지 않고 디버깅할 수 있다.

주의할 게 있다. 실행 이력은 설정에 따라 며칠 지나면 정리된다. “지난달에 몇 건 처리했지” 를 나중에 세려면 데이터가 없을 수 있다. 건수를 근거로 써야 한다면 처음부터 따로 적재해 두는 게 낫다.

버전 관리와 확장

Git 기반 버전 관리를 지원한다(환경 간 push-pull). 그리고 queue 모드로 워커를 분리해 확장할 수 있다. 다만 이건 워크플로가 상당히 늘어난 뒤의 얘기고, 처음부터 고민할 건 아니다.

설치

Docker 가 있으면 한 줄이다.

docker run -it --rm -p 5678:5678 -v n8n_data:/home/node/.n8n n8nio/n8n

localhost:5678 로 들어가면 끝. 볼륨을 안 붙이면 워크플로가 컨테이너와 함께 사라지니 -v 는 빼지 말 것.

실제로 굴릴 거면 두 가지를 더 본다.

웹훅을 쓸 거면 외부에서 닿는 주소가 필요하다. 시간 트리거만 쓸 거면 상관없지만, 외부 서비스가 호출해야 하면 도메인과 인증서가 붙는다.

기본 SQLite 는 개인용이다. 실행 이력이 쌓이면 느려진다. 워크플로가 늘어날 것 같으면 처음부터 PostgreSQL 로 가는 게 싸다.

n8n 을 백엔드로 쓴다는 것

사내 앱을 하나 만들어야 했다. 원래대로면 서버를 띄우고 API 를 짜고 DB 스키마를 잡아야 한다. 그러지 않고 웹훅 30개를 엔드포인트로 놓고 끝냈다. 별도 서버도 DB 도 없다.

대응은 이렇게 된다.

보통의 백엔드n8n
REST 엔드포인트Webhook 노드
비즈니스 로직Code 노드
cron / 스케줄러Schedule 트리거
외부 API 호출HTTP Request 노드
인증Credential + 헤더 검증

얻은 건 배포가 없다는 점이다. 로직을 고치고 저장하면 그게 배포다. 요구가 자주 바뀌는 사내 도구에서 이게 크다.

공짜는 아니다. 타입도 테스트도 없고 로직이 커지면 화면에서 읽기 어려워진다. 판단 기준은 “6개월 뒤에도 이 모양일 것 같은가” 다. 계속 바뀔 것 같으면 n8n, 굳을 것 같으면 코드로 옮긴다.

어떤 업무에 맞나

실제로 붙여서 남은 유형 넷이다.

1. 인입 처리. 문의 메일을 5분 주기로 읽어 업무 도구에 카드로 등록한다. 월 250건 규모에서 수기 등록이 사라졌고 월 5시간쯤 줄었다. 쓰는 기능은 메일 트리거 + 전용 노드 + 중복 제거.

2. 정기 검증. 결재 문서를 5분 주기로 훑어 규칙 위반을 찾는다. 날짜·합의자·증빙 금액이 본문과 맞는지를 기계 규칙으로 거르고 애매한 건 LLM 에 넘긴다. 월 55건 기준으로 문서당 3분씩 줄었다.

3. 1차 진단. 비개발자가 한 줄 쓰면 로그와 지표를 훑어 요약과 다음 행동을 돌려준다. 건당 30분~3시간이 20분이 됐다. 월 130건이면 21시간쯤이다.

4. 반복 작업 대체. 패턴이 정해진 수기 작업을 자동 진단하고 결과를 제시한다. 사람은 검토만 한다. 케이스당 30분~2시간이 10분으로 줄었고 누적 242건 처리했다.

공통점이 보인다. 로직이 복잡한 게 아니라 연결이 많고, 그 연결이 자주 바뀌는 일이다.

어디엔 쓰지 마라

코드 몇 줄이면 되는 일. cron 에 스크립트 하나 걸면 끝날 걸 노드로 만들면 관리 대상만 는다. 안 바뀔 로직이면 코드가 낫다.

대량 처리. 실행마다 이력이 쌓이는 구조다. 초당 수백 건 도는 파이프라인에 쓰면 그게 먼저 무너진다.

틀리면 돈이 나가는 일. 결제, 정산 실행, 재고 차감. 트랜잭션과 테스트가 필요한 영역이다. 정산 건도 진단과 결과 제시까지만 n8n 이 하고 적용은 사람이 했다. 그 선은 넘지 않는 게 맞다.

이미 다른 게 하고 있는 일. CI 가 배포 알림을 보내는데 한 겹 더 얹으면, 알림이 두 번 오거나 CI 가 조용히 죽었을 때 아무도 모른다.

20개가 넘어가면서 겪은 것들

여기부터는 워크플로가 늘어난 뒤에야 보이는 것들이다. 하나 만들 때는 안 보인다.

공통 조각을 빼두지 않으면 채널 교체가 지옥이 된다

메신저 발송, 알림 라우팅, 담당자 조회. 이런 조각이 워크플로마다 복사돼 있으면 알림 채널을 바꿀 때 20군데를 고쳐야 한다. 그리고 반드시 두세 개를 빠뜨린다.

별도 워크플로로 빼서 서브 워크플로로 호출하게 했다. 이름에 lib_ 접두어를 붙여 목록에서 구분되게 했다. 10개쯤 넘어갈 때 하는 게 아니라 3개째에 하는 게 맞다 — 그때는 5분이고 20개일 때는 하루다.

잡 큐를 새로 만들지 마라

여러 건을 순차 처리해야 할 때 큐가 필요해진다. 여기서 DB 테이블을 만들고 상태 컬럼을 넣고 싶어지는데, 그러면 상태를 볼 화면도 만들어야 한다.

이미 쓰는 업무 도구의 칸반 보드를 그대로 큐로 썼다. 카드가 특정 컬럼으로 옮겨지면 처리하고, 결과를 카드에 코멘트로 남긴다. 진행 상황은 담당자가 원래 보던 화면에서 그대로 보인다. 큐를 따로 만들었으면 그 화면을 새로 만들어야 했다.

프롬프트를 워크플로 안에 박지 마라

LLM 노드 파라미터에 프롬프트를 직접 쓰면, 문구 한 줄 고칠 때마다 워크플로를 열고 노드를 찾아 들어가야 한다. 39개 노드짜리 파이프라인에서는 그 자체가 일이 된다.

프롬프트를 밖으로 빼고 워크플로는 그걸 읽어오게 했다. 문구 수정과 파이프라인 수정이 분리되고, 프롬프트만 버전을 따로 관리할 수 있다.

실행 이력은 근거로 못 쓴다

앞에서도 짚었지만 한 번 더 강조할 만하다. “지난달 몇 건 처리했나” 를 나중에 세려고 하면 데이터가 없다.

성과를 보고해야 하거나 개선 전후를 비교해야 한다면, 처음부터 별도 저장소에 적재해야 한다. 나중에 아쉬워도 복구할 방법이 없다. 이건 설정으로 보존 기간을 늘려도 근본 해결이 아니다 — DB 가 그만큼 커진다.

실패 알림이 없으면 그건 완성이 아니다

가장 많이 빠지고 가장 아픈 항목이다. 자동화는 성공할 때가 아니라 조용히 멈췄을 때 문제가 된다.

앞의 Error workflow 절이 그 답이다. 하나 만들어서 전 워크플로에 같은 걸 지정하면 되고, 5분이면 끝난다. 이걸 안 하면 두 달 뒤에 “그거 그동안 안 돌고 있었어” 를 듣게 된다.

순서를 정하자면 이렇다. 워크플로를 만들고 → Error workflow 를 붙이고 → 그다음에 활성화한다. 활성화부터 하면 붙이는 걸 잊는다.

정리

n8n 은 연결이 많고 자주 바뀌는 업무에 맞다. 로직이 복잡하거나 정확성이 생명인 일은 코드가 낫다.

72개를 만들어보고 남은 기준은 하나다. 6개월 뒤에도 이 로직이 그대로일 것 같으면 코드로, 계속 바뀔 것 같으면 n8n 으로. 그 판단만 맞으면 나머지는 화면 보면서 배운다.

그리고 세 개는 처음부터 해두는 게 싸다 — Error workflow, 공통 조각 분리, 건수 별도 적재. 셋 다 나중에 하면 몇 배가 든다.