Creating Custom Nodes
Relevant source files
The following files were used as context for generating this wiki page:
Creating custom nodes is a core extensibility feature of n8n, allowing developers to integrate new services, add custom logic, and expand the platform's capabilities. The n8n ecosystem provides a suite of command-line tools to streamline the creation, development, and publication of these nodes. This guide covers the entire lifecycle, from scaffolding a new node to understanding its fundamental structure and development workflow.
The process is primarily managed through the @n8n/create-node and @n8n/node-cli packages, which offer a guided experience and a set of scripts for common development tasks. Nodes can be either "programmatic", offering full control with TypeScript, or "declarative", which are ideal for simpler REST APIs and can be configured with JSON.
Sources: CONTRIBUTING.md:213-214, packages/@n8n/create-node/README.md:3-5, packages/@n8n/create-node/README.md:143-145
Node Creation and Scaffolding
The quickest way to start building a custom node is by using the official scaffolding tool. This tool generates a new project with all the necessary boilerplate, configurations, and development scripts.
Sources: packages/@n8n/create-node/README.md:7-9
Quick Start Command
To create a new n8n node project, run the following command and follow the interactive prompts:
npm create @n8n/node@latest
The CLI will guide you through the setup process, asking for the node's name, the type of node you are building (e.g., HTTP API), the desired template, and other relevant details like API base URL and authentication type.
Sources: packages/@n8n/create-node/README.md:7-9, packages/@n8n/create-node/README.md:30-49
Available Templates
The scaffolding tool provides several templates to choose from, catering to different use cases:
| Template | Description | Best For |
|---|---|---|
declarative/custom | A minimal declarative node structure. | REST APIs, simple integrations. |
declarative/github-issues | An example of a GitHub Issues integration. | Learning declarative patterns. |
programmatic/example | A full programmatic node with advanced features. | Complex logic, custom operations. |
Sources: packages/@n8n/create-node/README.md:23-27, packages/@n8n/create-node/README.md:141-145
Generated Project Structure
The generated project follows a standard structure that the n8n development tools expect:
my-awesome-api-node/
├── src/
│ ├── nodes/
│ │ └── MyAwesomeApi/
│ │ ├── MyAwesomeApi.node.ts # Main node logic
│ │ └── MyAwesomeApi.node.json # Node metadata
│ └── credentials/
│ └── MyAwesomeApiAuth.credentials.ts
├── package.json
├── tsconfig.json
└── README.md
The package.json file is pre-configured with an n8n object that tells n8n where to find the compiled node and credential files.
{
"name": "n8n-nodes-my-awesome-node",
"n8n": {
"n8nNodesApiVersion": 1,
"nodes": [
"dist/nodes/MyAwesomeApi/MyAwesomeApi.node.js"
],
"credentials": [
"dist/credentials/MyAwesomeApiAuth.credentials.js"
]
}
}
Sources: packages/@n8n/create-node/README.md:118-130, packages/@n8n/create-node/README.md:134-140
Development Workflow
The development lifecycle is managed by npm scripts that wrap the @n8n/node-cli tool. The following diagram illustrates the typical workflow.
This diagram shows the development cycle for creating a custom n8n node.
Key Development Commands
The generated project includes several scripts to aid in development:
| Command | Description | Underlying CLI Command |
|---|---|---|
npm run dev | Starts n8n in development mode with hot reload for your node. | n8n-node dev |
npm run build | Compiles TypeScript and bundles the node for production. | n8n-node build |
npm run lint | Lints the code to check for style and convention issues. | n8n-node lint |
npm run lint:fix | Automatically fixes linting issues. | n8n-node lint --fix |
npm run release | Handles the entire release process, including versioning, tagging, and publishing to npm. | n8n-node release |
Sources: packages/@n8n/create-node/README.md:79-99, packages/@n8n/node-cli/README.md:12-31
Hot Reloading
When developing nodes, you can enable hot reload to see changes without restarting the server by setting the N8N_DEV_RELOAD environment variable.
N8N_DEV_RELOAD=true pnpm dev
This is particularly useful for iterating on node logic quickly. The watcher monitors file changes and automatically rebuilds and re-links the node into the running n8n instance.
Sources: CONTRIBUTING.md:110-114
Node Anatomy
A custom node is defined by a TypeScript class that implements the INodeType interface. This class contains a description property and an execution method.
Sources: packages/node-dev/README.md:37-41
INodeTypeDescription
The description property holds all the metadata for the node, which n8n uses to render it in the editor UI and understand its behavior.
| Property | Type | Required | Description |
|---|---|---|---|
displayName | string | Yes | The user-friendly name displayed in the Editor UI. |
name | string | Yes | The internal, unique name for the node (e.g., myNode). |
group | string[] | Yes | The node group for categorization (e.g., ['transform']). |
version | number | Yes | The version of the node, currently always 1. |
description | string | Yes | A short description of what the node does. |
defaults | object | Yes | Default name and color for the node when created. |
inputs | string[] | Yes | The types and number of inputs the node has (e.g., ['main']). |
outputs | string[] | Yes | The types and number of outputs the node has (e.g., ['main']). |
properties | INodeProperties[] | Yes | An array of properties (parameters) the user can configure. |
icon | string | No | An icon to display (e.g., icon: 'file:myNode.svg'). |
subtitle | string | No | Text displayed under the node name, can be an expression. |
credentials | INodeCredential[] | No | Credentials the node requires access to. |
Sources: packages/node-dev/README.md:125-150
Node Properties
The properties array defines the fields that users see in the node's parameter panel. Each property is an object with its own set of attributes.
| Property | Type | Required | Description |
|---|---|---|---|
displayName | string | Yes | The label for the property field in the UI. |
name | string | Yes | The internal name of the property (in camelCase). |
type | string | Yes | The data type of the property (e.g., string, number, options). |
default | any | Yes | The default value for the property. |
description | string | Yes | A description displayed to the user. |
placeholder | string | No | Placeholder text for the input field. |
required | boolean | No | Whether the property must have a value. |
options | object[] | No | For options or collection types, defines the available choices. |
Sources: packages/node-dev/README.md:152-165
Execution Methods
The core logic of a node is implemented in one of three possible execution methods. A node must have exactly one of these.
execute(Regular Node): Called when the workflow is executed. This is the most common method and provides the most flexibility, as it can return a different number of items than it receives.trigger(Trigger Node): Called once when the workflow is activated. It can then trigger workflow runs independently.webhook(Webhook Node): Called when the node's specific webhook URL is invoked.
The following diagram shows how n8n decides which method to call.
Sources: packages/node-dev/README.md:83-123
Example Node Implementation
Here is a simple example of a regular node from the n8n-node-dev documentation.
import {
IExecuteFunctions,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
export class MyNode implements INodeType {
description: INodeTypeDescription = {
displayName: 'My Node',
name: 'myNode',
group: ['transform'],
version: 1,
description: 'Adds "myString" on all items to defined value.',
defaults: {
name: 'My Node',
color: '#772244',
},
inputs: ['main'],
outputs: ['main'],
properties: [
// Node properties which the user gets displayed and
// can change on the node.
{
displayName: 'My String',
name: 'myString',
type: 'string',
default: '',
placeholder: 'Placeholder value',
description: 'The description text',
}
]
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
let item: INodeExecutionData;
let myString: string;
// Itterates over all input items and add the key "myString" with the
// value the parameter "myString" resolves to.
// (This could be a different value for each item in case it contains an expression)
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
myString = this.getNodeParameter('myString', itemIndex, '') as string;
item = items[itemIndex];
item.json['myString'] = myString;
}
return [items];
}
}
Sources: packages/node-dev/README.md:43-81
AI-Assisted Node Creation
The n8n platform includes an AI-powered tool, add_nodes, designed to programmatically add nodes to a workflow. This tool is part of the AI workflow builder and uses a structured input schema to create, name, and position nodes.
Sources: packages/@n8n/ai-workflow-builder.ee/src/tools/add-node.tool.ts
add_nodes Tool Logic
The tool follows a clear sequence to add a node to the workflow canvas.
This flowchart shows the logic of the AI add_node tool.
Input Schema
The tool's input is validated against a Zod schema, which requires the node type, a descriptive name, and reasoning for any connection-related parameters.
| Parameter | Type | Description |
|---|---|---|
nodeType | string | The type of node to add (e.g., n8n-nodes-base.httpRequest). |
name | string | A descriptive name for the node's purpose. |
connectionParametersReasoning | string | An explanation of why certain connection parameters are being used. |
connectionParameters | object | Parameters that affect node connections (e.g., mode, operation). |
Sources: packages/@n8n/ai-workflow-builder.ee/src/tools/add-node.tool.ts:22-45
Summary
The n8n platform provides a comprehensive and developer-friendly toolchain for creating custom nodes. By leveraging npm create @n8n/node, developers can quickly scaffold a new project with a robust development workflow, including hot reloading and automated release management. Understanding the core INodeType interface and the structure of node properties is key to building powerful and user-friendly integrations. With these tools, extending n8n's functionality becomes a streamlined and efficient process.
Sources: CONTRIBUTING.md:213-214, packages/@n8n/create-node/README.md