Building Custom Nodes
Relevant source files
The following files were used as context for generating this wiki page:
Custom nodes are the fundamental building blocks of n8n workflows. They allow developers to extend the platform by creating new integrations or data manipulation tools. Developers can build these nodes as community packages (prefixed with n8n-nodes- or @org/n8n-nodes-) or contribute them directly to the base package.
Sources: packages/@n8n/node-cli/src/template/templates/shared/default/AGENTS.md, CONTRIBUTING.md:27-40
Node Architecture and Interfaces
Every node must implement the INodeType interface. This interface defines the node's metadata, UI configuration, and execution logic. The structure of a node project typically separates the main node logic and the credentials used for authentication.
Core Structure
A standard node package follows this directory structure:
nodes/: Contains node folders (e.g.,nodes/Example/Example.node.ts).credentials/: Contains credential definitions (e.g.,credentials/Example.credentials.ts).package.json: Includes a specialn8nfield that points to the transpiled JS files.
Sources: packages/@n8n/node-cli/src/template/templates/shared/default/AGENTS.md
Node Class Components
The INodeType implementation requires specific properties and methods based on the node's function:
| Component | Description |
|---|---|
description | Defines INodeTypeDescription (metadata, properties, and UI config). |
execute() | Main logic for programmatic nodes. |
poll() | Logic for polling triggers (requires polling: true). |
trigger() | Logic for generic triggers. |
webhook() | Logic for webhook-based triggers. |
methods | Helper methods for loadOptions, listSearch, or credentialTest. |
Sources: packages/nodes-base/AGENTS.md:5-13
Development Styles
n8n supports two primary styles for developing nodes: Declarative and Programmatic.
Declarative Nodes
Declarative nodes use configuration rather than custom code to define API interactions. They rely on requestDefaults and routing configurations to handle HTTP requests.
Sources: packages/nodes-base/AGENTS.md:18-20, packages/@n8n/create-node/README.md
Programmatic Nodes
Programmatic nodes implement the execute function. This allows for complex custom logic, data manipulation, and multi-step API interactions that cannot be handled by simple routing.
Sources: packages/nodes-base/AGENTS.md:15-16
The following diagram illustrates the relationship between these components:
The diagram shows how the INodeType interface branches into different implementation styles while sharing common metadata and helper methods.
Sources: packages/nodes-base/AGENTS.md:5-20
Node Parameters and UI
Nodes interact with users through parameters defined in the description. These parameters use specific types to render UI elements in the n8n editor.
Common Parameter Types
- string: Basic text input.
- options: A dropdown menu. Can be static or dynamic via
loadOptionsMethod. - resourceLocator: A complex selector supporting list, ID, or URL modes.
- collection/fixedCollection: Structured key-value pairs or nested objects.
Sources: packages/nodes-base/AGENTS.md:32-41
Dynamic Data and Visibility
Developers use displayOptions to show or hide fields based on other parameter values. For selectors that should not support expressions, the noDataExpression: true flag is used.
Sources: packages/nodes-base/AGENTS.md:41-43
Creating a New Node
The recommended workflow for creating a custom node involves using the @n8n/create-node scaffolding tool.
Scaffolding and Setup
- Run
npm create @n8n/node@latest. - Select the node type (Declarative or Programmatic).
- Configure the base URL and authentication type.
- Navigate to the directory and run
npm run dev.
Sources: packages/@n8n/create-node/README.md
Development and Hot Reload
Setting the environment variable N8N_DEV_RELOAD=true enables hot reloading. This uses a file watcher to detect changes in node directories and automatically reloads the node definitions without a full server restart.
Sources: CONTRIBUTING.md:166-180, packages/@n8n/create-node/README.md
The sequence diagram shows the development loop when building nodes using the n8n CLI tools.
Sources: CONTRIBUTING.md:166-180, packages/@n8n/create-node/README.md
Testing Custom Nodes
Testing is mandatory for nodes to ensure reliability and handle edge cases.
Unit Testing
Unit tests use vitest and should mock all external dependencies. Developers use vitest-mock-extended to mock the IExecuteFunctions and INode interfaces.
- Happy Path: Verifies normal operation with valid inputs.
- Error Handling: Uses
NodeOperationErrororNodeApiErrorfor failures. - Binary Data: Tests file uploads and downloads.
Sources: packages/nodes-base/TESTING_PROMPT.md:12-40, packages/nodes-base/AGENTS.md:65-71
Workflow Testing
The NodeTestHarness allows developers to run integration tests using actual JSON workflow definitions. This is the preferred way to verify that a node functions correctly within a complete graph.
Sources: packages/nodes-base/AGENTS.md:73-76, packages/nodes-base/TESTING_PROMPT.md:180-190
Security Best Practices
Security is critical when handling user-provided data within nodes.
Untrusted Input
Never use untrusted values as computed object keys in assignments. This prevents prototype pollution attacks. Use n8n-workflow helpers like setSafeObjectProperty and isSafeObjectProperty when writing dynamic keys.
Sources: packages/nodes-base/AGENTS.md:100-115
Error Reporting
Avoid using the deprecated ApplicationError. Instead, use specific error classes based on the cause:
- UserError: For invalid user input.
- OperationalError: For transient network or API issues.
- UnexpectedError: For bugs in the node logic.
Sources: AGENTS.md:270-280
Conclusion
Building custom nodes requires implementing the INodeType interface and adhering to n8n's architectural standards. By using the official CLI tools for scaffolding and following security guidelines regarding untrusted input and error handling, developers can create robust, production-ready integrations for the n8n ecosystem.