面向已经会一点 JavaScript/TypeScript、用过 n8n 的同学,带你按官方文档的节奏,一步步把“自定义节点”真正跑起来。
n8n 自带了大量节点,但在实际项目里你经常会遇到:
这时候,“自定义节点”就是官方推荐的方式:
你可以像官方节点一样,在左侧节点面板里搜索到它,拖拽、配置、连线即可。
官方“Creating Nodes”文档把整个过程拆成五步:规划 → 构建 → 测试 → 部署 → 维护/分享。
| 步骤 | 对应官方文档 | 你要做的事情(简化版) |
|---|---|---|
| 规划 (Plan) | Plan a node | 选好节点类型、构建风格、UI 参数、文件结构 |
| 构建 (Build) | Build a node | 写 TypeScript / 声明式配置,实现节点逻辑 |
| 测试 (Test) | Test a node | 在本地 n8n 手动跑 + 用 linter 自动检查 |
| 部署 (Deploy) | Deploy a node | 本地私有安装,或发布为社区节点,供云端使用 |
| 概览 (Overview) | Creating nodes | 总体说明、参考链接、UI 元素 & 文件结构参考 |
n8n 的节点开发属于前端 TypeScript + 后端 HTTP/业务逻辑的结合,但官方已经把接口与约定封装得比较好,照着套路走即可。
下面这类界面就是你开发节点后要用到的工作流编辑器:左侧选节点,中间拖线,右侧配置参数。

要跟着本教程动手,建议你先准备好:
npm init、npm install、npm publish 基本命令)npx n8n 直接启动(默认 http://localhost:5678)/home/node/.n8n,例如:docker run -it --rm \
--name n8n \
-p 5678:5678 \
-e N8N_COMMUNITY_PACKAGES_ENABLED=true \
-v ~/n8n-data:/home/node/.n8n \
docker.n8n.io/n8nio/n8n其中 N8N_COMMUNITY_PACKAGES_ENABLED=true 是加载社区/自定义节点所必需的环境变量。
这一阶段只动脑,不动手写代码,目标是把以下四件事想清楚。
常见的有两大类:
新手建议:先从“普通节点”开始。
例如:封装一个“调用公开 HTTP API”并返回 JSON 的节点。
官方文档目前主推两种“节点构建风格”:
execute() 里的业务代码,更接近“配置一个 HTTP 集成”execute 方法里写 TypeScript 逻辑:初学建议:先做一个“声明式 HTTP 节点”,体验打通全流程。
n8n 的节点 UI 本质上是“一个配置结构”,内部渲染成表单。
常见字段类型:
你需要想清楚:
Method = GET。一个简单示例:封装猫咪语录 API 的节点
Cat Factlimit(返回条数,数字,默认 1)onlyText(布尔,默认 true,表示只输出文本字段)一个最小的自定义节点包,大致目录结构如下:
my-n8n-cat-node/
├─ package.json # 声明 n8n 节点、依赖、名字等
├─ tsconfig.json # TypeScript 配置(可复用官方模板)
├─ nodes/
│ └─ CatFact.node.ts # 具体节点实现文件
└─ credentials/ # 若需要鉴权(本例不需要,可为空)在 package.json 里,需要有一个 n8n 字段,告诉 n8n:
nodescredentials(如果有)下面以“调用公开猫咪语录 API:https://catfact.ninja/fact”为例,写一个最小可用的节点骨架。
注意:代码是结构示意,重点是帮助你理解,不是完整生产代码。
在你本机某个目录下:
mkdir my-n8n-cat-node
cd my-n8n-cat-node
npm init -y随后:
devDependencies)tsconfig.json(可直接照官方模板)在 package.json 中增加类似配置(示例):
{
"name": "my-n8n-cat-node",
"version": "0.1.0",
"main": "dist/nodes/index.js",
"n8n": {
"nodes": [
"dist/nodes/CatFact.node.js"
],
"credentials": []
},
"scripts": {
"build": "tsc",
"lint": "eslint ."
}
}要点:
n8n.nodes 数组里列出编译后的节点文件路径(通常在 dist 下).ts),构建后输出 JS (.js)nodes/CatFact.node.ts 示例结构(删掉了一些高级配置,只保留最关键部分,帮助你看清“形状”):
import type {
INodeType,
INodeTypeDescription,
IExecuteFunctions,
} from 'n8n-workflow';
export class CatFact implements INodeType {
description: INodeTypeDescription = {
displayName: 'Cat Fact',
name: 'catFact',
group: ['transform'],
version: 1,
description: 'Get random cat facts from catfact.ninja',
defaults: {
name: 'Cat Fact',
},
inputs: ['main'],
outputs: ['main'],
properties: [
{
displayName: 'Limit',
name: 'limit',
type: 'number',
typeOptions: {
minValue: 1,
maxValue: 10,
},
default: 1,
description: 'How many facts to fetch',
},
{
displayName: 'Only Text',
name: 'onlyText',
type: 'boolean',
default: true,
description: 'Return only fact text field',
},
],
};
async execute(this: IExecuteFunctions) {
const items = this.getInputData();
const returnData = [];
const limit = this.getNodeParameter('limit', 0) as number;
const onlyText = this.getNodeParameter('onlyText', 0) as boolean;
// 简单写法:只看第一条输入 item,执行一次请求
const response = await this.helpers.request({
method: 'GET',
uri: 'https://catfact.ninja/facts',
qs: { limit },
json: true,
});
const facts = response?.data || [];
for (const fact of facts) {
if (onlyText) {
returnData.push({ json: { fact: fact.fact } });
} else {
returnData.push({ json: fact });
}
}
return [returnData];
}
}这里混合了“声明式 UI”(properties)和“代码式 execute”,是最常见的模式:
UI 用配置描述,逻辑用 TypeScript 写。
完整的类型定义(
INodeTypeDescription各字段含义、UI 元素种类)可以在官方 “Build a declarative-style node” 文档与参考章节里查到。
官方文档推荐两种测试方式都用上:手动测试 + linter 自动检查。
常见方式(以 Docker、自定义包为例):
npm run buildcustom 下,例如:cd ~/n8n-data
mkdir -p custom
cd custom
# 假设你已经在别处写好包,可以用 npm 安装或直接拷贝
npm i /path/to/my-n8n-cat-node-v ~/n8n-data:/home/node/.n8n
-e N8N_COMMUNITY_PACKAGES_ENABLED=truedocker stop n8n && <之前的 docker run 命令>docker compose restartn8n 只会在启动时扫描 custom 目录里的包,所以每次装新节点后必须重启。
Cat Fact 节点,拖到画布上Cat Fact 节点Cat Fact,在右侧参数面板里设置:Limit = 3Only Text = true官方提供了节点 linter,用于检查:
基本使用方式:
package.json 里添加一个 lint 脚本(官方模板里通常已给出)npm run lint具体 linter 的安装命令与配置请以官方 “Test a node” 文档为准;教程里保持概念即可,避免跟版本耦合过死。
当你在本地反复测试、linter 通过后,就可以考虑“给别人用”了。
如果只是团队内部 / 自己用,有两个简单方式:
custom 目录~/n8n-data/custom 里 npm i my-n8n-cat-node@latest 然后重启即可这种方式在自托管 n8n 中很常见,适合企业内网集成。
如果希望别人能在 n8n 云端(hosted)直接安装你的节点,需要:
官方也明确:在云端想用自定义节点,只能通过“社区节点”的方式安装,不能像本地那样直接挂个 custom 目录。
最后给一个完整可执行工作流 JSON 作为实战练习,让你熟悉:
nodes、connections 等)示例来自一个公开的 n8n 工作流数据集中:
它做的事情非常简单:
注意:要真正发送短信,你需要一个 Plivo 账号和有效的手机号码,这里只是展示结构与导入方法。
你可以直接复制下面这段 JSON,在 n8n 中导入并运行(记得先配置 Plivo 凭据)。
{
"name": "",
"nodes": [
{
"name": "On clicking 'execute'",
"type": "n8n-nodes-base.manualTrigger",
"position": [250, 300],
"parameters": {},
"typeVersion": 1
},
{
"name": "Plivo",
"type": "n8n-nodes-base.plivo",
"position": [500, 300],
"parameters": {
"to": "+14156667778",
"from": "+14156667777",
"message": "Hello world!"
},
"credentials": {
"plivoApi": ""
},
"typeVersion": 1
}
],
"active": false,
"settings": {},
"connections": {
"On clicking 'execute'": {
"main": [
[
{
"node": "Plivo",
"type": "main",
"index": 0
}
]
]
}
}
}这个 JSON 的几个关键点:
nodes 数组里有两个节点:n8n-nodes-base.manualTriggern8n-nodes-base.plivoconnections 描述了连线关系:active: false 表示导入后默认不自动激活,需要手动点“激活工作流”才会定时/触发执行这一结构与官方的“导出/导入工作流”文档描述是一致的:
n8n 会把工作流保存为 JSON,其中 nodes、connections、name 等是导入时的关键字段。
Plivo 节点Credentials 下拉里选择你已经配置好的 Plivo 凭据to、from 改成你自己的测试号码如果一切配置正确,你会收到一条 “Hello world!” 短信。
练习题:现在你已经有了 Cat Fact 节点,可以试试这样改造:
Plivo 节点Cat Fact 节点Manual Trigger → Cat FactCat Fact 输出的 JSON 数据进一步挑战:
Cat Fact 后面再加一个官方的 Edit Fields (Set) 节点,把 fact 字段改名为 message,为后续短信/通知做准备。这就是一个完整闭环:
规划节点 → 编写节点 → 测试节点 → 部署节点 → 在真实工作流中使用它。
通过这篇教程,你已经掌握了:
description + 实现 executecustom 目录、启用社区包、手动执行下一步可以做什么?
[1] 官方文档: https://docs.n8n.io/integrations/creating-nodes/overview/
[2] n8n系列教程: https://www.undsky.com/blog/?category=n8n%E6%95%99%E7%A8%8B#