Agent skill
n8n-syntax-node-types
Use when creating custom n8n nodes, defining node properties, implementing execute methods, or building declarative nodes. Prevents incorrect INodeProperties types and malformed displayOptions conditions. Covers INodeType interface, INodeTypeDescription, INodeProperties (22 types), displayOptions with rich conditions, execute() method with IExecuteFunctions, Node base class alternative, versioned nodes, declarative routing, and methods (loadOptions, listSearch, credentialTest, resourceMapping). Keywords: n8n, custom nodes, INodeType, INodeProperties, execute, displayOptions, declarative routing, versioned nodes, credentialTest.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/n8n-syntax-node-types
Metadata
Additional technical details for this skill
- author
- OpenAEC-Foundation
- version
- 1.0
SKILL.md
n8n-syntax-node-types
Quick Reference
INodeType Interface Members
| Member | Signature | Required | Purpose |
|---|---|---|---|
description |
INodeTypeDescription |
YES | Node metadata, properties, credentials |
execute |
(this: IExecuteFunctions) => Promise<INodeExecutionData[][]> |
For regular nodes | Process input items |
trigger |
(this: ITriggerFunctions) => Promise<ITriggerResponse> |
For event triggers | Emit data on events |
poll |
(this: IPollFunctions) => Promise<INodeExecutionData[][] | null> |
For polling triggers | Periodically check for data |
webhook |
(this: IWebhookFunctions) => Promise<IWebhookResponseData> |
For webhook nodes | Handle HTTP requests |
supplyData |
(this: ISupplyDataFunctions, itemIndex: number) => Promise<SupplyData> |
For AI sub-nodes | Provide data to AI agents |
methods |
{ loadOptions, listSearch, credentialTest, resourceMapping, actionHandler } |
No | Dynamic methods |
webhookMethods |
{ [name]: { checkExists, create, delete } } |
No | External webhook lifecycle |
INodeTypeDescription Key Fields
| Field | Type | Required | Notes |
|---|---|---|---|
displayName |
string |
YES | Human-readable name in UI |
name |
string |
YES | Internal identifier (e.g., 'myNode') |
icon |
string | { light, dark } |
No | 'fa:icon-name' or 'file:icon.svg' |
group |
NodeGroupType[] |
YES | 'input', 'output', 'transform', 'trigger', 'schedule' |
version |
number | number[] |
YES | Supported versions |
description |
string |
YES | Short description |
defaults |
{ name: string } |
YES | Default node name |
inputs |
NodeConnectionType[] | ExpressionString |
YES | Input connections |
outputs |
NodeConnectionType[] | ExpressionString |
YES | Output connections |
credentials |
INodeCredentialDescription[] |
No | Required credential types |
properties |
INodeProperties[] |
YES | Node parameters |
polling |
true |
No | Marks node as polling trigger |
webhooks |
IWebhookDescription[] |
No | Webhook registrations |
requestDefaults |
HttpRequestOptions |
No | Declarative base URL/headers |
usableAsTool |
true |
No | Enable as AI agent tool |
subtitle |
string |
No | Dynamic expression for UI subtitle |
All 22 Property Types (NodePropertyTypes)
| Type | UI Element | Default Value Type |
|---|---|---|
'boolean' |
Toggle switch | boolean |
'button' |
Action button | string |
'collection' |
Group of optional fields | {} |
'color' |
Color picker | string |
'dateTime' |
Date/time picker | string |
'fixedCollection' |
Group with fixed structure | {} |
'hidden' |
Hidden value | string |
'icon' |
Icon selector | string |
'json' |
JSON editor | string |
'callout' |
Info/warning callout | string |
'notice' |
Notice/info text | string |
'multiOptions' |
Multi-select dropdown | string[] |
'number' |
Number input | number |
'options' |
Single-select dropdown | string |
'string' |
Text input | string |
'credentialsSelect' |
Credential selector | string |
'resourceLocator' |
Resource locator (ID/URL/list) | object |
'curlImport' |
cURL import | string |
'resourceMapper' |
Resource field mapper | object |
'filter' |
Filter/condition builder | object |
'assignmentCollection' |
Field assignment collection | object |
'workflowSelector' |
Workflow selector | string |
'credentials' |
Credentials property | string |
IExecuteFunctions Key Methods
| Method | Signature | Purpose |
|---|---|---|
getInputData |
(inputIndex?: number) => INodeExecutionData[] |
Get input items |
getNodeParameter |
(name: string, itemIndex: number) => any |
Read parameter value |
getCredentials |
(type: string) => Promise<ICredentialDataDecryptedObject> |
Get decrypted credentials |
continueOnFail |
() => boolean |
Check continue-on-fail setting |
executeWorkflow |
(workflowInfo, inputData?) => Promise<ExecuteWorkflowData> |
Call sub-workflow |
putExecutionToWait |
(waitTill: Date) => Promise<void> |
Pause execution until date |
sendMessageToUI |
(message: any) => void |
Send message to editor UI |
helpers.httpRequest |
(options) => Promise<any> |
Make HTTP requests |
helpers.getBinaryDataBuffer |
(itemIndex, propertyName) => Promise<Buffer> |
Read binary data |
helpers.prepareBinaryData |
(buffer, fileName?, mimeType?) => Promise<IBinaryData> |
Create binary data |
helpers.normalizeItems |
(items) => INodeExecutionData[] |
Normalize item format |
Critical Warnings
ALWAYS return INodeExecutionData[][] from execute() -- the outer array represents output indices (for multi-output nodes like IF/Switch), the inner array contains items. Single-output nodes return [returnData].
ALWAYS iterate over input items using this.getInputData() and call getNodeParameter(name, i) with the item index i -- parameters can contain expressions that resolve differently per item.
ALWAYS handle continueOnFail() in the catch block of your item loop -- when enabled, push an error item with pairedItem instead of throwing.
NEVER use &str or borrowed types in node parameters -- n8n uses IDataObject (plain objects) for all parameter values. Cast with as string, as number, etc.
NEVER create an execute() method in declarative nodes -- n8n handles HTTP requests automatically based on routing configuration in properties.
NEVER define inputs on trigger nodes -- trigger nodes ALWAYS have inputs: [] (empty array) because they start workflow execution.
NEVER use this binding in the Node base class -- the Node class passes context as a parameter. Use context.getInputData() instead of this.getInputData().
ALWAYS set noDataExpression: true on resource and operation selector properties -- these properties control node behavior and MUST NOT be expression-dependent.
Decision Trees
Which Node Pattern to Use?
Is this a trigger/starting node?
├── YES: Does it respond to HTTP requests?
│ ├── YES → Webhook pattern (webhook() + webhooks config)
│ └── NO: Does it poll an external service?
│ ├── YES → Poll pattern (poll() + polling: true)
│ └── NO → Trigger pattern (trigger() + emit())
└── NO: Is this a simple REST API wrapper?
├── YES → Declarative pattern (routing in properties, NO execute())
└── NO → Programmatic pattern (execute() with custom logic)
Which Property Type to Use?
What data does the user provide?
├── True/false → 'boolean'
├── Free text → 'string' (add rows for textarea, editor for code)
├── A number → 'number' (set minValue/maxValue in typeOptions)
├── One choice from list → 'options'
├── Multiple choices from list → 'multiOptions'
├── A set of optional fields → 'collection'
├── A structured group of fields → 'fixedCollection'
├── Raw JSON → 'json'
├── Date/time → 'dateTime'
├── A color → 'color'
├── Filter conditions → 'filter'
├── Field mapping → 'resourceMapper'
├── Field assignments → 'assignmentCollection'
├── Resource ID/URL/name → 'resourceLocator'
├── Another workflow → 'workflowSelector'
└── Display-only info → 'notice' or 'callout'
Essential Patterns
Pattern 1: Programmatic Node (implements INodeType)
import type {
IExecuteFunctions,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
export class MyNode implements INodeType {
description: INodeTypeDescription = {
displayName: 'My Node',
name: 'myNode',
icon: 'file:myIcon.svg',
group: ['transform'],
version: 1,
description: 'Processes data',
defaults: { name: 'My Node' },
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
properties: [/* see references/methods.md */],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: INodeExecutionData[] = [];
for (let i = 0; i < items.length; i++) {
try {
const value = this.getNodeParameter('myParam', i) as string;
returnData.push({ json: { result: value } });
} catch (error) {
if (this.continueOnFail()) {
returnData.push({
json: { error: (error as Error).message },
pairedItem: { item: i },
});
continue;
}
throw error;
}
}
return [returnData]; // Single output
}
}
Pattern 2: Node Base Class (context parameter)
import { Node } from 'n8n-workflow';
import type {
IExecuteFunctions,
INodeExecutionData,
INodeTypeDescription,
} from 'n8n-workflow';
export class MyNode extends Node {
description: INodeTypeDescription = { /* same as above */ };
async execute(
context: IExecuteFunctions // context parameter, NOT this
): Promise<INodeExecutionData[][]> {
const items = context.getInputData(); // Use context, not this
const returnData: INodeExecutionData[] = [];
for (let i = 0; i < items.length; i++) {
const value = context.getNodeParameter('myParam', i) as string;
returnData.push({ json: { result: value } });
}
return [returnData];
}
}
Pattern 3: Declarative Node (routing, NO execute)
export class ApiNode implements INodeType {
description: INodeTypeDescription = {
displayName: 'API Node',
name: 'apiNode',
group: ['input'],
version: 1,
description: 'Interacts with an API',
defaults: { name: 'API Node' },
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
credentials: [{ name: 'myApi', required: true }],
requestDefaults: {
baseURL: 'https://api.example.com',
headers: { Accept: 'application/json' },
},
properties: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Get Many',
value: 'getAll',
action: 'Get many items',
routing: {
request: { method: 'GET', url: '/items' },
},
},
],
default: 'getAll',
},
],
};
// NO execute() method -- n8n handles requests via routing
}
Pattern 4: displayOptions (Conditional Properties)
// Show 'limit' only when operation is 'getAll' AND returnAll is false
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
typeOptions: { minValue: 1 },
displayOptions: {
show: {
operation: ['getAll'],
returnAll: [false],
},
},
}
// Rich conditions with operators
{
displayName: 'Advanced Field',
name: 'advancedField',
type: 'string',
default: '',
displayOptions: {
show: {
'@version': [{ _cnd: { gte: 2 } }], // Version 2+
status: [{ _cnd: { not: 'archived' } }], // Not archived
},
},
}
Pattern 5: Versioned Node
import type { IVersionedNodeType, INodeType } from 'n8n-workflow';
export class MyNodeVersioned implements IVersionedNodeType {
currentVersion = 2;
description = { /* INodeTypeBaseDescription */ };
nodeVersions: { [key: number]: INodeType } = {
1: new MyNodeV1(),
2: new MyNodeV2(),
};
getNodeType(version?: number): INodeType {
return this.nodeVersions[version ?? this.currentVersion];
}
}
Pattern 6: methods Object (Dynamic Loading)
methods = {
loadOptions: {
async getUsers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const credentials = await this.getCredentials('myApi');
const users = await this.helpers.httpRequest({ /* ... */ });
return users.map((u: any) => ({ name: u.name, value: u.id }));
},
},
listSearch: {
async searchUsers(
this: ILoadOptionsFunctions,
filter?: string,
paginationToken?: string,
): Promise<INodeListSearchResult> {
// Return { results: [...], paginationToken?: string }
},
},
credentialTest: {
async testMyApi(this: ICredentialTestFunctions): Promise<INodeCredentialTestResult> {
// Return { status: 'OK', message: 'Success' }
// or { status: 'Error', message: 'Invalid credentials' }
},
},
resourceMapping: {
async getFields(this: ILoadOptionsFunctions): Promise<ResourceMapperFields> {
// Return field definitions for resource mapper
},
},
};
INodeExecutionData Structure
interface INodeExecutionData {
json: IDataObject; // REQUIRED -- the main data payload
binary?: IBinaryKeyData; // Optional binary/file data
error?: NodeApiError; // Error info if item errored
pairedItem?: IPairedItemData | number; // Source item linking
}
// Binary data keyed by property name
interface IBinaryKeyData {
[key: string]: IBinaryData; // e.g., { data: {...}, attachment: {...} }
}
ALWAYS include a json property on every output item -- it is the only required field. Binary data is ALWAYS secondary.
execute() Return Type
The return type INodeExecutionData[][] is a 2D array:
- Outer array: One entry per output connector (index 0 = first output, index 1 = second output)
- Inner array: Items for that output
// Single output (most nodes):
return [returnData];
// Two outputs (like IF node):
return [trueItems, falseItems];
// Three outputs:
return [output1Items, output2Items, output3Items];
// Empty output (no items):
return [[]];
Reference Links
- references/methods.md -- INodeType, INodeTypeDescription, INodeProperties (all 22 types), IDisplayOptions, IExecuteFunctions
- references/examples.md -- Complete node implementation, property definitions, displayOptions, declarative node
- references/anti-patterns.md -- Node type mistakes, property configuration errors
Official Sources
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?