G: 안녕하세요, 자동화와 효율성을 사랑하는 모든 분들! 🤖 오늘은 오픈 소스 워크플로우 자동화 도구인 n8n을 한 단계 더 강력하게 만들어 줄 ‘나만의 커스텀 노드 개발’ 여정에 대해 이야기해 보려 합니다. n8n은 수많은 내장 노드를 제공하지만, 때로는 우리의 특정 요구사항을 완벽하게 충족시키지 못할 때가 있죠. 그럴 때 필요한 것이 바로 커스텀 노드입니다!
이 글에서는 n8n 커스텀 노드를 처음부터 끝까지 개발하고, 디버깅하며, 최종적으로 배포하는 모든 과정을 자세히 다룰 예정입니다. 복잡해 보이지만, 차근차근 따라오시면 여러분의 워크플로우를 정말 “춤추게” 만들 수 있을 거예요! 💃🕺
🚀 1. 왜 n8n 커스텀 노드를 개발해야 할까요?
n8n의 내장 노드들은 대부분의 일반적인 시나리오를 커버합니다. 하지만 다음과 같은 상황에서는 커스텀 노드 개발이 필수적입니다.
- 내부 시스템/레거시 API 연동: 회사에서만 사용하는 특정 내부 시스템이나 오래된 레거시 API는 n8n에 내장되어 있지 않습니다. 이럴 때 커스텀 노드를 만들어 연동할 수 있습니다. 🏢
- 특정 데이터 변환 로직: 복잡한 데이터 변환, 특정 알고리즘 적용, 여러 데이터를 조합하는 등 고유한 비즈니스 로직이 필요할 때 유용합니다.
- 아직 n8n에 없는 서비스 연동: 세상에는 정말 많은 SaaS 서비스가 있고, n8n이 모든 서비스를 커버할 수는 없습니다. 내가 원하는 서비스가 없으면 직접 만들어 사용하거나 커뮤니티에 공유할 수 있습니다. 🌐
- 재사용성 및 표준화: 특정 기능을 여러 워크플로우에서 반복적으로 사용해야 할 때, 커스텀 노드로 만들어두면 편리하게 재사용하고 관리할 수 있습니다.
- 커뮤니티 기여: 내가 만든 유용한 노드를 다른 사람들과 공유하여 n8n 생태계를 더욱 풍요롭게 만들 수 있습니다. 🤝
결국, 커스텀 노드 개발은 n8n의 한계를 넘어서 여러분의 자동화 가능성을 무한대로 확장하는 열쇠입니다! 🔑
🛠️ 2. 개발 환경 설정: 첫걸음 떼기
본격적인 개발에 앞서, 필요한 도구들을 설치하고 프로젝트를 초기화해야 합니다.
2.1. 필수 준비물
- Node.js: n8n 노드는 TypeScript(JavaScript의 상위 집합)로 작성됩니다. Node.js 런타임이 필요하며, n8n이 지원하는 최신 LTS 버전을 사용하는 것을 권장합니다 (예: Node.js 16 이상).
- 설치 확인:
node -v
- 설치 확인:
- npm 또는 Yarn: Node.js 패키지 매니저입니다. Node.js 설치 시 함께 설치됩니다.
- 설치 확인:
npm -v
또는yarn -v
- 설치 확인:
- n8n 인스턴스: 개발 중인 노드를 테스트할 n8n 인스턴스가 필요합니다. 로컬에서
n8n start
로 실행하거나, 이미 구동 중인 n8n 서버를 사용할 수 있습니다. - VS Code (권장): TypeScript 개발에 최적화된 강력한 코드 에디터입니다. 💻
2.2. 프로젝트 초기화: n8n init
의 마법 ✨
n8n은 커스텀 노드 개발을 위한 CLI(명령줄 인터페이스) 도구를 제공합니다. n8n init
명령어를 사용하면 필요한 모든 파일과 폴더 구조를 자동으로 생성해 줍니다.
-
새 폴더 생성 및 이동:
mkdir my-custom-n8n-nodes cd my-custom-n8n-nodes
-
n8n CLI로 프로젝트 초기화:
n8n init
이 명령어를 실행하면 몇 가지 질문에 답하게 됩니다:
Package Name
:n8n-nodes-my-awesome-tool
(관례적으로n8n-nodes-
접두사를 사용합니다)Node Name
:MyAwesomeTool
(노드 이름, 대소문자 구분)Node Type
:Regular
(일반 노드),Trigger
(워크플로우를 시작하는 노드),Webhook
(웹훅 수신 노드) 중 선택.Use TypeScript?
:Yes
(강력 권장!)
성공적으로 초기화되면 다음과 같은 기본적인 파일 구조가 생성됩니다:
my-custom-n8n-nodes/ ├── package.json // 프로젝트 정보 및 의존성 ├── tsconfig.json // TypeScript 설정 ├── .eslintrc.json // ESLint 설정 (코드 품질) ├── .prettierrc.json // Prettier 설정 (코드 포맷팅) ├── nodes/ │ └── MyAwesomeTool/ │ ├── MyAwesomeTool.node.ts // 노드 핵심 로직 파일 │ └── MyAwesomeTool.ts // (선택적) 추가 로직 파일 └── credentials/ └── MyAwesomeToolApi.credentials.ts // API 키 등 자격 증명 파일 (필요시)
2.3. 의존성 설치
n8n init
으로 프로젝트를 초기화한 후에는 필요한 Node.js 패키지들을 설치해야 합니다.
npm install
# 또는
yarn install
이제 기본적인 개발 환경 설정은 완료되었습니다! 🎉
🧩 3. 노드 개발의 핵심: Anatomy of a Node
이제 nodes/MyAwesomeTool/MyAwesomeTool.node.ts
파일을 열어보세요. 이 파일이 바로 여러분의 커스텀 노드의 심장입니다. n8n 노드는 크게 세 가지 주요 부분으로 구성됩니다:
INodeTypeDescription
(노드 메타데이터): 노드의 이름, 아이콘, 설명, 입력 필드 등 노드의 “생김새”와 사용자 인터페이스를 정의합니다.ICredentialType
(자격 증명): API 키, OAuth 토큰 등 민감한 정보를 안전하게 관리하는 방법을 정의합니다. (선택 사항, 필요시credentials/
폴더에 정의)execute
메서드 (핵심 로직): 노드가 실제로 어떤 작업을 수행할지 정의하는 부분입니다.
3.1. INodeTypeDescription
: 노드의 얼굴 🎭
MyAwesomeTool.node.ts
파일 상단에 description
객체가 있습니다.
// nodes/MyAwesomeTool/MyAwesomeTool.node.ts
import { INodeType, INodeTypeDescription } from 'n8n-workflow';
export class MyAwesomeTool implements INodeType {
description: INodeTypeDescription = {
displayName: '나의 멋진 도구', // n8n UI에 표시될 노드 이름
name: 'myAwesomeTool', // 내부에서 사용될 노드 고유 이름 (스네이크 케이스)
icon: 'file:myAwesomeTool.svg', // 노드 아이콘 (SVG 파일)
group: ['transform'], // 노드가 속할 그룹 (예: 'transform', 'data', 'utility')
version: 1, // 노드 버전 (업데이트 시 변경)
description: '나만의 아주 특별한 도구입니다.', // 노드 설명
defaults: {
name: '나의 멋진 도구 노드',
},
inputs: ['main'], // 입력 노드 허용 ('main'은 기본 입력)
outputs: ['main'], // 출력 노드 허용 ('main'은 기본 출력)
credentials: [
{
name: 'myAwesomeToolApi', // credentials 폴더에 정의한 이름과 일치
required: false, // 자격 증명이 필수인지 여부
},
],
properties: [ // 노드에 표시될 입력 필드들
{
displayName: '텍스트 입력',
name: 'myTextInput',
type: 'string',
default: '안녕하세요, n8n!',
placeholder: '여기에 텍스트를 입력하세요',
description: '노드에 전달할 텍스트입니다.',
},
{
displayName: '숫자 입력',
name: 'myNumberInput',
type: 'number',
default: 123,
description: '노드에 전달할 숫자입니다.',
},
{
displayName: '옵션 선택',
name: 'mySelectOption',
type: 'options',
options: [
{
name: '옵션 A',
value: 'optionA',
},
{
name: '옵션 B',
value: 'optionB',
},
],
default: 'optionA',
description: '선택 가능한 옵션입니다.',
},
// ... 더 많은 타입의 필드를 추가할 수 있습니다 (boolean, dateTime, json, multiOptions 등)
],
};
// ... execute 메서드
}
properties
: 이곳에 정의된 객체들이 n8n 워크플로우 빌더에서 노드를 클릭했을 때 보이는 입력 필드들입니다.type
속성에 따라 다양한 종류의 입력 필드를 제공할 수 있습니다. 예를 들어,string
,number
,boolean
,options
,json
,dateTime
등이 있습니다.
3.2. ICredentialType
: 보안 관리 🛡️
API 키와 같은 민감 정보는 credentials
폴더에 별도의 파일로 정의하여 안전하게 관리합니다. n8n init
시 자격 증명 파일 생성을 선택했다면, credentials/MyAwesomeToolApi.credentials.ts
파일이 생성됩니다.
// credentials/MyAwesomeToolApi.credentials.ts
import { ICredentialType, INodeProperties } from 'n8n-workflow';
export class MyAwesomeToolApi implements ICredentialType {
name = 'myAwesomeToolApi'; // description.ts의 credentials.name과 일치해야 함
displayName = '나의 멋진 도구 API 인증';
documentationUrl = 'https://example.com/api-docs'; // API 문서 링크
properties: INodeProperties[] = [
{
displayName: 'API 키',
name: 'apiKey',
type: 'string',
default: '',
typeOptions: { password: true }, // 비밀번호처럼 마스킹
description: '당신의 멋진 도구 API 키',
},
// ... 필요한 다른 인증 정보 (예: username, password)
];
}
typeOptions: { password: true }
를 사용하면 UI에서 입력값이 별표(****)로 표시되어 보안을 강화할 수 있습니다.
3.3. execute
메서드: 노드의 두뇌 🧠
이 메서드는 워크플로우가 실행될 때마다 호출되며, 노드의 핵심 비즈니스 로직을 포함합니다. 입력 데이터(아이템), 노드 설정, 자격 증명 등에 접근하여 원하는 작업을 수행하고 결과를 다음 노드로 전달합니다.
// nodes/MyAwesomeTool/MyAwesomeTool.node.ts (MyAwesomeTool 클래스 내부)
import { IExecuteFunctions } from 'n8n-workflow'; // import 추가
// ... description 객체 아래에 추가
async execute(this: IExecuteFunctions): Promise {
const items = this.getInputData(); // 이전 노드에서 전달된 데이터 아이템들을 가져옴
const returnData: INodeExecutionData[][] = []; // 결과를 담을 배열
for (let i = 0; i < items.length; i++) {
// 1. 노드 설정(properties) 값 가져오기
const myTextInput = this.getNodeParameter('myTextInput', i) as string;
const myNumberInput = this.getNodeParameter('myNumberInput', i) as number;
const mySelectOption = this.getNodeParameter('mySelectOption', i) as string;
// 2. 자격 증명(credentials) 가져오기 (필요시)
const credentials = await this.getCredentials('myAwesomeToolApi') as { apiKey: string };
const apiKey = credentials.apiKey;
// 3. 핵심 비즈니스 로직 (예: 외부 API 호출)
console.log(`API 키: ${apiKey ? '존재함' : '없음'}`); // 디버깅 용
console.log(`입력 텍스트: ${myTextInput}`);
console.log(`입력 숫자: ${myNumberInput}`);
console.log(`선택된 옵션: ${mySelectOption}`);
// 예시: 간단한 데이터 변환 또는 조합
const processedData = {
originalText: myTextInput,
transformedText: myTextInput.toUpperCase(), // 텍스트를 대문자로 변환
doubledNumber: myNumberInput * 2,
selectedOption: mySelectOption,
timestamp: new Date().toISOString(),
};
// 4. 결과 반환
// 각 입력 아이템에 대해 새로운 데이터 아이템을 생성하여 반환합니다.
// n8n은 데이터를 "아이템" 단위로 처리하며, 각 아이템은 JSON 객체입니다.
returnData.push([ { json: processedData } ]);
}
return returnData; // 처리된 데이터를 다음 노드로 전달
}
}
this.getInputData()
: 이전 노드에서 넘어온 데이터를 가져옵니다. n8n은 데이터를Item
객체의 배열로 다룹니다.this.getNodeParameter(name, itemIndex)
:description
에 정의된 입력 필드 값을 가져옵니다.itemIndex
는 현재 처리 중인 아이템의 인덱스입니다.this.getCredentials(name)
:credentials
에 정의된 자격 증명 정보를 가져옵니다.- 오류 처리: 외부 API 호출 시
try...catch
블록을 사용하여 예외를 처리하고,this.setError()
를 사용하여 n8n 워크플로우에 오류를 알릴 수 있습니다. - 데이터 반환:
INodeExecutionData[][]
형태의 데이터를 반환합니다. 일반적으로[[ { json: yourResultObject } ]]
와 같이 각 입력 아이템에 대해 하나의 출력 아이템을 만듭니다.
🐞 4. 춤추는 워크플로우를 위한 디버깅 팁
개발된 노드가 제대로 작동하는지 확인하는 것은 매우 중요합니다. n8n은 노드 개발을 위한 강력한 디버깅 환경을 제공합니다.
4.1. n8n dev
명령: 개발 모드 실행
프로젝트 루트 폴더에서 다음 명령을 실행하면, n8n이 개발 모드로 시작되며, 커스텀 노드를 자동으로 로드합니다. 코드 변경 시 자동으로 재컴파일되어 n8n에 반영됩니다.
npm run dev
# 또는
n8n dev
n8n dev
를 실행하면 n8n 스튜디오가 열리고, 왼쪽 노드 목록에서 여러분이 개발 중인 노드를 찾을 수 있습니다.
4.2. console.log()
활용
가장 기본적인 디버깅 방법입니다. execute
메서드 내부에 console.log()
를 삽입하여 변수 값, 실행 흐름 등을 확인할 수 있습니다.
// execute 메서드 내부
console.log('--- 노드 실행 시작 ---');
console.log('받은 입력 텍스트:', myTextInput);
// ...
console.log('--- 노드 실행 완료 ---');
이 로그들은 n8n dev
를 실행한 터미널에 출력됩니다.
4.3. VS Code 디버거 연결 🧪
보다 심층적인 디버깅을 위해서는 VS Code의 디버거를 연결하는 것이 좋습니다.
launch.json
설정: VS Code에서.vscode/launch.json
파일을 생성하거나 수정합니다.{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "attach", "name": "Attach to n8n", "port": 9229, // n8n이 디버깅 포트로 사용하는 기본 포트 "restart": true, "protocol": "inspector", "skipFiles": [ "/**" ] } ] }
- n8n 개발 모드 실행 (디버거 활성화):
NODE_OPTIONS='--inspect=9229' n8n dev
또는
package.json
스크립트에 추가:"scripts": { "dev": "NODE_OPTIONS='--inspect=9229' n8n dev", // ... }
이제
npm run dev
(또는yarn dev
)로 실행합니다. - VS Code에서 디버거 연결: VS Code의 “실행 및 디버그” 탭으로 이동하여
Attach to n8n
설정을 선택하고 재생 버튼을 누릅니다. - 중단점 설정:
MyAwesomeTool.node.ts
파일에서 원하는 코드 라인에 중단점(빨간 점)을 설정합니다. - 워크플로우 실행: n8n 스튜디오에서 워크플로우를 실행하면, 코드가 중단점에서 멈추고 VS Code에서 변수 값 확인, 단계별 실행 등을 할 수 있습니다. 🔍
4.4. 에러 핸들링: 튼튼한 노드 만들기 💥
노드 실행 중 예상치 못한 오류가 발생할 수 있습니다. try...catch
문을 사용하여 외부 API 호출 등 오류가 발생할 수 있는 부분을 감싸고, this.setError(item, error)
를 사용하여 n8n에 오류를 보고하는 것이 중요합니다.
async execute(this: IExecuteFunctions): Promise {
const items = this.getInputData();
const returnData: INodeExecutionData[][] = [];
for (let i = 0; i < items.length; i++) {
try {
const myTextInput = this.getNodeParameter('myTextInput', i) as string;
// ... 다른 설정 및 자격 증명
// 예시: 외부 API 호출 (가상)
const apiResponse = await fetch(`https://api.example.com/process?text=${myTextInput}`);
if (!apiResponse.ok) {
throw new Error(`API 호출 실패: ${apiResponse.statusText}`);
}
const result = await apiResponse.json();
returnData.push([ { json: { success: true, data: result } } ]);
} catch (error) {
// 오류 발생 시 n8n에 오류를 보고하고, 해당 아이템의 처리를 중단하지 않고 다음 아이템으로 넘어갈 수 있게 함
this.setError(items[i], error as Error);
returnData.push([ { json: { success: false, error: (error as Error).message } } ]); // 실패 처리된 아이템도 반환 가능
}
}
return returnData;
}
this.setError
를 사용하면 워크플로우 실행 기록에서 어떤 아이템에서 오류가 발생했는지 명확하게 확인할 수 있습니다.
🚢 5. 노드 배포와 공유: 세상에 내놓기
커스텀 노드 개발이 완료되었다면, 이제 n8n 인스턴스에 설치하여 사용하거나 다른 사람들과 공유할 수 있습니다.
5.1. 로컬 배포: 내 n8n에서 사용하기
개발한 노드를 내 n8n 인스턴스에 설치하는 가장 간단한 방법입니다.
-
노드 빌드: 프로젝트 루트 폴더에서 다음 명령을 실행하여 TypeScript 코드를 JavaScript로 컴파일합니다.
npm run build # 또는 yarn build
이 명령은
dist
폴더에 컴파일된 JavaScript 파일을 생성합니다. -
n8n 커스텀 노드 폴더로 복사: 컴파일된 파일을 n8n의 커스텀 노드 폴더로 복사합니다. 이 폴더의 위치는 n8n 설정에 따라 다르지만, 일반적으로 사용자 홈 디렉토리 내에 있습니다.
- Linux/macOS:
~/.n8n/custom/
- Windows:
%USERPROFILE%\.n8n\custom\
또는C:\Users\\.n8n\custom\
# Linux/macOS 예시 cp -r dist/* ~/.n8n/custom/
dist
폴더 아래의 모든 내용을custom
폴더로 복사해야 합니다.
- Linux/macOS:
-
n8n 재시작: n8n 인스턴스를 재시작하여 새로운 노드를 로드합니다.
n8n start
이제 n8n 스튜디오에서 여러분의 노드를 검색하여 사용할 수 있습니다! 🎉
5.2. 프라이빗/내부 배포: 팀 내에서 공유 🔒
회사나 팀 내부에서만 노드를 공유해야 할 경우, 다음과 같은 방법을 고려할 수 있습니다.
- Git 서브모듈: n8n 인스턴스의
~/.n8n/custom/
폴더에 Git 서브모듈로 커스텀 노드 저장소를 추가합니다. - Private npm Registry: Verdaccio와 같은 프라이빗 npm 레지스트리를 설정하고, 여기에 노드 패키지를 게시하여
npm install
을 통해 설치할 수 있도록 합니다. -
Docker 빌드에 포함: n8n을 Docker로 배포하는 경우, Dockerfile에 커스텀 노드 빌드 및 복사 단계를 포함시켜 이미지를 빌드합니다.
# Dockerfile 예시 FROM n8nio/n8n:latest # 커스텀 노드 소스 코드 복사 COPY ./my-custom-n8n-nodes /usr/local/lib/node_modules/my-custom-n8n-nodes # 의존성 설치 및 빌드 WORKDIR /usr/local/lib/node_modules/my-custom-n8n-nodes RUN npm install && npm run build # 빌드된 노드를 n8n 커스텀 노드 폴더로 이동 RUN mv ./dist/* /root/.n8n/custom/ WORKDIR /usr/local/lib/node_modules/n8n
5.3. 퍼블릭 배포: n8n 커뮤니티와 공유 🌐
여러분의 노드가 범용적으로 유용하다고 생각된다면, npm에 게시하고 n8n 커뮤니티에 기여할 수 있습니다.
package.json
준비:package.json
의name
,version
,description
,keywords
,repository
,author
,license
필드를 적절히 채웁니다.main
필드가dist/index.js
를 가리키는지 확인합니다.files
필드를 추가하여dist
폴더만 포함되도록 합니다 ("files": ["dist"]
).
- npm 로그인:
npm login
명령어로 npm 계정에 로그인합니다. - npm publish:
npm publish
- 주의:
n8n-nodes-
접두사를 사용한 패키지 이름은 npm에서 n8n 팀에서 소유하고 있을 수 있으므로, 미리 확인하거나 다른 이름을 고려해야 합니다. - 일반적으로 개인 개발자는
n8n-community-nodes-your-name-tool
또는 단순히your-tool-n8n-node
와 같이 이름을 짓습니다.
- 주의:
- n8n 커뮤니티에 제출: n8n은 커뮤니티 노드를 위한 별도의 저장소(
n8n-io/n8n-nodes-base
)를 운영하며, 여기에 풀 리퀘스트를 통해 공식적으로 노드를 추가할 수 있습니다. n8n 공식 문서의 “Contribution Guide”를 참조하세요. 이는 노드의 품질과 유지보수를 n8n 팀이 검토한다는 의미이므로, 신뢰도를 높일 수 있습니다.
✅ 6. 꿀팁과 모범 사례
- TypeScript의 강력함 활용: TypeScript는 타입 안정성을 제공하여 개발 중 흔한 오류를 줄여줍니다.
n8n init
으로 생성된 기본 템플릿도 TypeScript를 사용합니다. - 견고한 오류 처리: 외부 API 호출은 언제든 실패할 수 있습니다.
try...catch
를 사용하여 오류를 우아하게 처리하고,this.setError()
를 통해 사용자에게 명확한 피드백을 제공하세요. - 상태 코드 및 재시도: 외부 API와 연동 시 HTTP 상태 코드(예: 4xx, 5xx)를 적절히 처리하고, 필요하다면 재시도(Retry) 로직을 구현하여 일시적인 네트워크 문제에 강건하게 만드세요.
- 문서화: 노드에 대한 명확한 설명(
description.description
), 각 속성에 대한 자세한 설명(properties.description
)을 제공하세요. 이는 노드를 사용하는 다른 사람들에게 큰 도움이 됩니다. README.md 파일에 사용법 예시를 추가하는 것도 좋습니다. - 테스팅: 가능하다면 Jest와 같은 도구를 사용하여 단위 테스트를 작성하여 노드 로직의 정확성을 검증하세요. (이 글에서는 다루지 않지만, 중요한 부분입니다).
- 보안: API 키, 비밀번호와 같은 민감 정보는 절대 하드코딩하지 마세요. 반드시
credentials
기능을 통해 안전하게 관리해야 합니다. - n8n 공식 문서 참고: n8n 공식 문서는 노드 개발에 대한 가장 정확하고 최신 정보를 제공합니다. 막히는 부분이 있다면 언제든 공식 문서를 참고하세요. (Node Development | n8n Docs)
🎉 마무리하며
이제 여러분은 n8n 커스텀 노드를 개발하고, 디버깅하며, 배포하는 전체 과정을 이해하셨을 겁니다. 처음에는 복잡하게 느껴질 수 있지만, 몇 번 시도해 보면 n8n의 무궁무진한 확장성에 감탄하게 될 것입니다.
나만의 노드를 만들어 워크플로우를 더욱 자동화하고, 반복적인 작업을 줄이며, 더 중요한 일에 집중할 시간을 확보하세요. 여러분의 아이디어가 n8n의 강력한 기능과 결합하여 놀라운 시너지를 낼 수 있기를 기대합니다! 🌟
궁금한 점이 있다면 언제든지 n8n 커뮤니티 포럼이나 GitHub 저장소를 찾아보세요. 활발한 커뮤니티가 여러분의 여정을 도울 준비가 되어 있습니다! 행복한 노드 개발 되세요! 🥳