Skip to main content

Node Execution

This guide covers the execution contexts and helper functions available to nodes during runtime.

Execution Contexts

Different node operations have access to different execution contexts, each providing specific capabilities.

IExecuteFunctions

The primary execution context for programmatic nodes.
export class MyNode implements INodeType {
  async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
    const items = this.getInputData();
    const returnData: INodeExecutionData[] = [];

    for (let i = 0; i < items.length; i++) {
      const resource = this.getNodeParameter('resource', i) as string;
      const operation = this.getNodeParameter('operation', i) as string;

      if (resource === 'user') {
        if (operation === 'get') {
          const userId = this.getNodeParameter('userId', i) as string;
          
          const responseData = await this.helpers.httpRequest({
            method: 'GET',
            url: `https://api.example.com/users/${userId}`,
          });

          returnData.push({
            json: responseData,
            pairedItem: { item: i },
          });
        }
      }
    }

    return [returnData];
  }
}

Core Methods

getInputData
function
required
Get input data from the previous node
getInputData(inputIndex?: number, connectionType?: NodeConnectionType): INodeExecutionData[]
getNodeParameter
function
required
Get parameter value for a specific item
getNodeParameter(
  parameterName: string,
  itemIndex: number,
  fallbackValue?: any,
  options?: IGetNodeParameterOptions,
): NodeParameterValueType | object
getNode
function
Get the current node object
getNode(): INode
getWorkflow
function
Get workflow metadata
getWorkflow(): IWorkflowMetadata
getWorkflowStaticData
function
Get/set persistent workflow data
getWorkflowStaticData(type: 'workflow' | 'node'): IDataObject
getCredentials
function
Get decrypted credentials
getCredentials<T = ICredentialDataDecryptedObject>(
  type: string,
  itemIndex?: number,
): Promise<T>
getExecutionId
function
Get the current execution ID
getExecutionId(): string
getMode
function
Get execution mode (manual, trigger, webhook, etc.)
getMode(): WorkflowExecuteMode

Advanced Methods

continueOnFail
function
Check if node should continue on error
continueOnFail(): boolean
evaluateExpression
function
Evaluate an n8n expression
evaluateExpression(expression: string, itemIndex: number): NodeParameterValueType
getContext
function
Get/set context data
getContext(type: 'flow' | 'node'): IContextObject
putExecutionToWait
function
Pause execution until specified time
putExecutionToWait(waitTill: Date): Promise<void>
sendMessageToUI
function
Send message to the UI
sendMessageToUI(message: any): void
executeWorkflow
function
Execute another workflow
executeWorkflow(
  workflowInfo: IExecuteWorkflowInfo,
  inputData?: INodeExecutionData[],
): Promise<ExecuteWorkflowData>

ITriggerFunctions

Execution context for trigger nodes.
Trigger Function Implementation
export class MyTrigger implements INodeType {
  async trigger(this: ITriggerFunctions): Promise<ITriggerResponse> {
    const webhookUrl = this.getNodeWebhookUrl('default');
    const pollInterval = this.getNodeParameter('pollInterval') as number;

    const interval = setInterval(async () => {
      try {
        const data = await this.helpers.httpRequest({
          method: 'GET',
          url: 'https://api.example.com/events',
        });

        if (data.length > 0) {
          this.emit([
            data.map((item: any) => ({
              json: item,
            })),
          ]);
        }
      } catch (error) {
        this.emitError(error as Error);
      }
    }, pollInterval * 1000);

    async function closeFunction() {
      clearInterval(interval);
    }

    return {
      closeFunction,
    };
  }
}
emit
function
required
Emit data to start workflow execution
emit(data: INodeExecutionData[][]): void
emitError
function
Report fatal trigger error and deactivate workflow
emitError(error: Error): void
saveFailedExecution
function
Persist failed execution but keep trigger active
saveFailedExecution(error: ExecutionError): void
getActivationMode
function
Get how the workflow was activated
getActivationMode(): WorkflowActivateMode

IPollFunctions

Execution context for polling trigger nodes.
Poll Function Implementation
export class MyPollingTrigger implements INodeType {
  async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> {
    const staticData = this.getWorkflowStaticData('node');
    const lastTimestamp = staticData.lastTimestamp as number || 0;

    const data = await this.helpers.httpRequest({
      method: 'GET',
      url: 'https://api.example.com/items',
      qs: { since: lastTimestamp },
    });

    if (data.length === 0) {
      return null; // No new data
    }

    // Update state
    staticData.lastTimestamp = Date.now();

    return [
      data.map((item: any) => ({
        json: item,
      })),
    ];
  }
}

IWebhookFunctions

Execution context for webhook nodes.
Webhook Function Implementation
export class MyWebhook implements INodeType {
  async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
    const bodyData = this.getBodyData();
    const headerData = this.getHeaderData();
    const queryData = this.getQueryData();
    const req = this.getRequestObject();
    const res = this.getResponseObject();

    // Process webhook data
    const processedData = {
      body: bodyData,
      headers: headerData,
      query: queryData,
    };

    return {
      workflowData: [[
        {
          json: processedData,
        },
      ]],
    };
  }
}
getBodyData
function
Get request body data
getBodyData(): IDataObject
getHeaderData
function
Get request headers
getHeaderData(): IncomingHttpHeaders
getQueryData
function
Get query parameters
getQueryData(): object
getRequestObject
function
Get Express request object
getRequestObject(): express.Request
getResponseObject
function
Get Express response object
getResponseObject(): express.Response

ILoadOptionsFunctions

Context for loading dynamic options.
Load Options Context
methods = {
  loadOptions: {
    async getProjects(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
      const credentials = await this.getCredentials('myApi');
      const workflowId = this.getWorkflow().id;
      
      const response = await this.helpers.httpRequest({
        method: 'GET',
        url: `${credentials.baseUrl}/projects`,
        headers: {
          'Authorization': `Bearer ${credentials.apiKey}`,
        },
      });

      return response.projects.map((project: any) => ({
        name: project.name,
        value: project.id,
        description: project.description,
      }));
    },
  },
};

Helper Functions

All execution contexts provide a helpers object with utility functions.

HTTP Requests

HTTP Request
const response = await this.helpers.httpRequest({
  method: 'POST',
  url: 'https://api.example.com/data',
  body: {
    name: 'John Doe',
    email: 'john@example.com',
  },
  headers: {
    'Content-Type': 'application/json',
  },
});

Binary Data

const buffer = Buffer.from('Hello World');
const binaryData = await this.helpers.prepareBinaryData(
  buffer,
  'output.txt',
  'text/plain',
);

returnData.push({
  json: {},
  binary: {
    data: binaryData,
  },
});

Data Transformation

returnJsonArray
function
Convert objects to node execution data array
const data = { name: 'John', age: 30 };
const items = this.helpers.returnJsonArray(data);
// Returns: [{ json: { name: 'John', age: 30 } }]
normalizeItems
function
Normalize data to execution format
const normalized = this.helpers.normalizeItems(
  items,
);
constructExecutionMetaData
function
Add pairedItem metadata to results
const results = this.helpers.constructExecutionMetaData(
  items,
  { itemData: { item: i } },
);

Deduplication

Prevent processing duplicate items in polling triggers.
Deduplication Helpers
async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> {
  const items = await fetchNewItems();
  
  // Check for and mark processed items
  const { new: newItems } = await this.helpers.checkProcessedAndRecord(
    items.map((item) => item.id),
    'node',
    {
      mode: 'latestIncrementalKey',
      maxEntries: 1000,
    },
  );

  if (newItems.length === 0) {
    return null;
  }

  return [
    items
      .filter((item) => newItems.includes(item.id))
      .map((item) => ({ json: item })),
  ];
}

File System

const filePath = this.getNodeParameter('filePath', 0) as string;
const resolvedPath = await this.helpers.resolvePath(filePath);

if (this.helpers.isFilePathBlocked(resolvedPath)) {
  throw new NodeOperationError(
    this.getNode(),
    'Access to this path is not allowed',
  );
}

Node Execution Data

The standard data format passed between nodes.
INodeExecutionData Structure
interface INodeExecutionData {
  json: IDataObject;           // Main JSON data
  binary?: IBinaryKeyData;     // Binary data by key
  pairedItem?: IPairedItemData | IPairedItemData[] | number;
  error?: NodeApiError | NodeOperationError;
  metadata?: {
    subExecution: RelatedExecution;
  };
}

Working with Items

Processing Items
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
  const items = this.getInputData();
  const returnData: INodeExecutionData[] = [];

  for (let i = 0; i < items.length; i++) {
    try {
      const inputItem = items[i];
      
      // Access JSON data
      const userId = inputItem.json.userId as string;
      
      // Access binary data
      const binaryData = inputItem.binary?.data;

      // Process and create output
      const result = await processData(userId);

      returnData.push({
        json: result,
        pairedItem: { item: i }, // Track source item
      });
    } catch (error) {
      if (this.continueOnFail()) {
        returnData.push({
          json: { error: error.message },
          pairedItem: { item: i },
        });
        continue;
      }
      throw new NodeOperationError(this.getNode(), error, { itemIndex: i });
    }
  }

  return [returnData];
}

Error Handling

import { NodeOperationError } from 'n8n-workflow';

if (!userId) {
  throw new NodeOperationError(
    this.getNode(),
    'User ID is required',
    { itemIndex: i },
  );
}

Best Practices

  • Process items in batches when possible
  • Use streaming for large files
  • Cache expensive operations
  • Implement proper pagination
  • Limit concurrent API requests

See Also