agentsclimarketplace

N8n syntax trigger nodes

Skill Impertio-Studio/n8n-Claude-Skill-Package/skills/source/n8n-syntax/n8n-syntax-trigger-nodes

21 deterministic Claude AI skills for n8n v1.x workflow automation

Install
npx -y skills add Impertio-Studio/n8n-Claude-Skill-Package --skill n8n-syntax-trigger-nodes

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when creating custom trigger nodes or implementing webhook/polling handlers in n8n v1.x. Prevents incorrect trigger lifecycle implementation by missing closeFunction or manualTriggerFunction. Covers three trigger patterns (event/timer, polling, webhook), ITriggerFunctions, IWebhookFunctions, IPollFunctions interfaces, ITriggerResponse, webhook lifecycle methods (checkExists/create/delete), and WebhookResponseMode types. Keywords: n8n, trigger node, webhook, polling, ITriggerFunctions, schedule, cron, every Monday, daily, hourly, recurring, start workflow automatically, polling..

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

12.1 KB, as published. Nobody here has run it

n8n Trigger Node Development

Build custom trigger nodes for n8n v1.x using event/timer, polling, or webhook patterns.

Quick Reference

PatternMethodInterfaceDescription KeyUse When
Event/Timertrigger()ITriggerFunctionsgroup: ['trigger']Listening to events, cron schedules, streams
Pollingpoll()IPollFunctionspolling: truePeriodically checking an API for new data
Webhookwebhook()IWebhookFunctionswebhooks: [...]External service sends HTTP requests to n8n

Critical Rules

  • ALWAYS set inputs: [] on trigger nodes — triggers have NO inputs
  • ALWAYS include 'trigger' in the group array
  • ALWAYS double-wrap emitted data: this.emit([[items]]) — outer array = outputs, inner array = items
  • ALWAYS provide manualTriggerFunction for event triggers so "Test Workflow" works in the editor
  • ALWAYS implement closeFunction when your trigger allocates resources (intervals, connections, listeners)
  • NEVER emit single-wrapped arrays — this.emit([items]) causes silent failures
  • NEVER forget cleanup — leaked intervals/connections persist across workflow deactivation

Decision Tree: Which Trigger Pattern?

Need a trigger node?
├── Does an EXTERNAL SERVICE call YOUR endpoint?
│   └── YES → Use WEBHOOK pattern (webhook() + IWebhookFunctions)
│       ├── Service has webhook registration API? → Add webhookMethods lifecycle
│       └── Service sends to a static URL? → Use webhooks[] description only
├── Do you need to CHECK an API periodically?
│   └── YES → Use POLLING pattern (poll() + IPollFunctions)
│       └── ALWAYS implement deduplication (track last seen ID/timestamp)
└── Do you LISTEN for events, run on schedule, or stream data?
    └── YES → Use EVENT/TIMER pattern (trigger() + ITriggerFunctions)
        └── ALWAYS implement closeFunction for cleanup

Pattern 1: Event/Timer Trigger

Use trigger() with ITriggerFunctions for schedule-based or event-driven triggers.

Minimal Structure

import type {
    ITriggerFunctions,
    INodeType,
    INodeTypeDescription,
    ITriggerResponse,
    INodeExecutionData,
} from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';

export class MyEventTrigger implements INodeType {
    description: INodeTypeDescription = {
        displayName: 'My Event Trigger',
        name: 'myEventTrigger',
        group: ['trigger'],          // REQUIRED for trigger nodes
        version: 1,
        inputs: [],                  // ALWAYS empty for triggers
        outputs: [NodeConnectionTypes.Main],
        defaults: { name: 'My Event Trigger' },
        properties: [/* ... */],
    };

    async trigger(this: ITriggerFunctions): Promise<ITriggerResponse> {
        const executeTrigger = () => {
            // CRITICAL: Double-wrap — [[items]]
            this.emit([[ { json: { timestamp: new Date().toISOString() } } ]]);
        };

        if (this.getMode() === 'manual') {
            // Editor "Test Workflow" mode
            return { manualTriggerFunction: async () => executeTrigger() };
        }

        // Production mode — set up persistent listener
        const intervalId = setInterval(executeTrigger, 60_000);

        // ALWAYS return closeFunction for cleanup
        return { closeFunction: async () => clearInterval(intervalId) };
    }
}

ITriggerResponse Fields

FieldTypePurpose
closeFunction() => Promise<void>Cleanup when workflow deactivated. ALWAYS implement when allocating resources.
manualTriggerFunction() => Promise<void>Simulates trigger for "Test Workflow" in editor. ALWAYS implement for event triggers.
manualTriggerResponsePromise<INodeExecutionData[][]>Alternative: promise that resolves when data is emitted.

Emitting Data

// CORRECT — double array wrapping
this.emit([[ { json: { key: 'value' } } ]]);

// CORRECT — multiple items in one emission
this.emit([[ { json: { id: 1 } }, { json: { id: 2 } } ]]);

// CORRECT — using helper for array conversion
this.emit([this.helpers.returnJsonArray([{ id: 1 }, { id: 2 }])]);

// WRONG — single array wrapping (SILENT FAILURE)
this.emit([{ json: { key: 'value' } }]);  // DO NOT DO THIS

Error Reporting

// Non-fatal: log error, workflow stays active
this.saveFailedExecution(error);

// Fatal: deactivates workflow, queues for reactivation with backoff
this.emitError(error);

Pattern 2: Polling Trigger

Use poll() with IPollFunctions for periodic API checks.

Minimal Structure

export class MyPollingTrigger implements INodeType {
    description: INodeTypeDescription = {
        displayName: 'My Polling Trigger',
        name: 'myPollingTrigger',
        group: ['trigger'],
        version: 1,
        polling: true,               // REQUIRED — marks as polling trigger
        inputs: [],
        outputs: [NodeConnectionTypes.Main],
        defaults: { name: 'My Polling Trigger' },
        properties: [
            {
                displayName: 'Poll Interval',
                name: 'pollInterval',
                type: 'options',
                default: 'every5Minutes',
                options: [
                    { name: 'Every Minute', value: 'everyMinute' },
                    { name: 'Every 5 Minutes', value: 'every5Minutes' },
                ],
            },
        ],
    };

    async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> {
        // Return null when no new data — NEVER return empty arrays
        // Return [[items]] when new data found
    }
}

Deduplication Pattern

ALWAYS implement deduplication for polling triggers to prevent duplicate processing.

async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> {
    const webhookData = this.getWorkflowStaticData('node');
    const lastTimestamp = webhookData.lastTimestamp as string | undefined;

    const items = await fetchNewItems(lastTimestamp);

    if (items.length === 0) {
        return null;  // ALWAYS return null for "no new data"
    }

    // Update stored state for next poll cycle
    webhookData.lastTimestamp = items[items.length - 1].updatedAt;

    return [items.map(item => ({ json: item }))];
}

Key: Use this.getWorkflowStaticData('node') to persist state between poll cycles. This data survives workflow restarts. ALWAYS update the stored marker after processing.

Pattern 3: Webhook Trigger

Use webhook() with IWebhookFunctions for HTTP-triggered workflows.

Minimal Structure

export class MyWebhookTrigger implements INodeType {
    description: INodeTypeDescription = {
        displayName: 'My Webhook Trigger',
        name: 'myWebhookTrigger',
        group: ['trigger'],
        version: 1,
        inputs: [],
        outputs: [NodeConnectionTypes.Main],
        defaults: { name: 'My Webhook Trigger' },
        webhooks: [
            {
                name: 'default',
                httpMethod: '={{$parameter["httpMethod"] || "POST"}}',
                path: '={{$parameter["path"]}}',
                responseMode: '={{$parameter["responseMode"]}}',
            },
        ],
        properties: [/* httpMethod, path, responseMode */],
    };

    async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
        const body = this.getBodyData();
        return { workflowData: [[ { json: body } ]] };
    }
}

WebhookResponseMode

ModeBehaviorUse When
onReceivedRespond immediately after webhook node executesFire-and-forget; caller does not need workflow result
lastNodeRespond after the LAST node in workflow finishesCaller needs the final processed result
responseNodeRespond from a dedicated "Respond to Webhook" nodeNeed custom response body/status at a specific point

IWebhookFunctions Methods

MethodReturnsPurpose
getBodyData()IDataObjectParsed request body
getHeaderData()IncomingHttpHeadersRequest headers
getQueryData()objectURL query parameters
getParamsData()objectURL path parameters
getRequestObject()express.RequestFull Express request (advanced)
getResponseObject()express.ResponseFull Express response (advanced, for manual response)
getNodeWebhookUrl('default')stringThe registered webhook URL

Webhook Lifecycle (webhookMethods)

For triggers that register webhooks on EXTERNAL services (e.g., GitHub, Stripe):

webhookMethods: {
    default: {
        async checkExists(this: IHookFunctions): Promise<boolean> {
            // Return true if webhook already registered on external service
        },
        async create(this: IHookFunctions): Promise<boolean> {
            // Register webhook URL on external service
            // Store webhook ID in static data for later deletion
            const webhookUrl = this.getNodeWebhookUrl('default');
            // ... API call to register ...
            return true;
        },
        async delete(this: IHookFunctions): Promise<boolean> {
            // Remove webhook from external service on deactivation
            return true;
        },
    },
},

Lifecycle: checkExists runs first. If false, create runs. On workflow deactivation, delete runs.

IWebhookResponseData Fields

FieldTypePurpose
workflowDataINodeExecutionData[][]Data passed into the workflow
webhookResponseanyCustom response sent back to the caller
noWebhookResponsebooleanSet true if you already sent a response via getResponseObject()

Trigger Node Description Requirements

Every trigger node description MUST include:

description: INodeTypeDescription = {
    group: ['trigger'],              // REQUIRED — identifies as trigger
    inputs: [],                      // REQUIRED — triggers have no inputs
    outputs: [NodeConnectionTypes.Main],
    // For polling triggers, add:
    polling: true,
    // For webhook triggers, add:
    webhooks: [{ name: 'default', httpMethod: '...', path: '...', responseMode: '...' }],
    // Optional but recommended:
    eventTriggerDescription: 'Waiting for events from MyService',
    activationMessage: 'Your trigger is now active and listening.',
};

Reference Files

FileContents
references/methods.mdComplete ITriggerFunctions, IWebhookFunctions, IPollFunctions, ITriggerResponse, webhookMethods, WebhookResponseMode
references/examples.mdFull implementations: schedule trigger, webhook trigger, polling trigger
references/anti-patterns.mdCommon trigger implementation mistakes and fixes

Sources

  • n8n-io/n8n GitHub: packages/workflow/src/interfaces.ts — ITriggerFunctions, IWebhookFunctions, IPollFunctions, ITriggerResponse
  • n8n-io/n8n GitHub: packages/nodes-base/nodes/Schedule/ScheduleTrigger.node.ts
  • n8n-io/n8n GitHub: packages/nodes-base/nodes/Webhook/Webhook.node.ts
  • n8n official docs: https://docs.n8n.io/integrations/creating-nodes/build/programmatic-style/

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.