agentsclimarketplace

N8n core architecture

Skill Impertio-Studio/n8n-Claude-Skill-Package/skills/source/n8n-core/n8n-core-architecture

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

Install
npx -y skills add Impertio-Studio/n8n-Claude-Skill-Package --skill n8n-core-architecture

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 building n8n workflows, creating custom nodes, understanding data flow, or debugging execution issues. Prevents incorrect INodeExecutionData structure and data flow mistakes. Covers item-based execution model, binary data handling, paired items, node types (trigger/regular), process modes (main/worker/queue), and workflow settings. Keywords: n8n, architecture, INodeExecutionData, execution model, binary data,, how n8n works, data flow, execution model, getting started, item structure. paired items, trigger nodes, queue mode, workflow settings.

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

11.7 KB, as published. Nobody here has run it

n8n-core-architecture

Quick Reference

Architecture Layers (n8n v1.x)

LayerTechnologyRole
Execution EngineNode.js + TypeScriptProcesses workflows as item sequences through nodes
Item PipelineINodeExecutionDataCarries JSON data, binary files, paired items, and errors
Node SystemINodeType interfaceDefines trigger, regular, webhook, polling, and declarative nodes
Expression EngineData ProxyProvides $json, $input, $binary, $execution, $workflow, $node
Process ModelMain / Worker / QueueScales from single-process to distributed queue mode
Workflow SettingsIWorkflowSettingsControls timezone, error handling, execution timeout, execution order

Execution Modes (WorkflowExecuteMode)

ModeTrigger
manualUser clicks "Execute Workflow" in editor
webhookHTTP webhook received
triggerTrigger node activated (schedule, poll)
retryRetrying a failed execution
cliCommand-line execution
errorError workflow triggered
integratedSub-workflow called from another workflow
internalInternal system execution
evaluationEvaluation/test execution
chatChat-based trigger

Node Types

TypeMethodInputsGroup
Regularexecute()Has inputs['transform'], ['input'], ['output']
Event Triggertrigger()No inputs['trigger']
Webhook Triggerwebhook()No inputs['trigger']
Polling Triggerpoll()No inputs['trigger'] (with polling: true)
DeclarativeNone (routing config)Has inputsAny

Critical Warnings

NEVER return a flat INodeExecutionData[] from execute() -- ALWAYS wrap in an outer array: return [returnData]. The outer array represents output indices (for multi-output nodes like IF/Switch).

NEVER mutate input items directly -- ALWAYS create new item objects. Mutating input items causes data corruption in downstream nodes that share the same reference.

NEVER ignore pairedItem in custom nodes that transform items -- ALWAYS set pairedItem: { item: i } to maintain item linking. Without paired items, n8n cannot trace data lineage.

NEVER assume item.binary exists -- ALWAYS check for undefined before accessing binary data. Not all items carry binary data.

NEVER use this.getNodeParameter('param', 0) with a hardcoded index when processing multiple items -- ALWAYS use the loop index i to get per-item parameter values.

NEVER skip continueOnFail() checks in custom nodes -- ALWAYS wrap item processing in try/catch and check this.continueOnFail() to respect user error settings.


Item-Based Execution Model

Data Flow

n8n processes data as items. Each node receives an array of items, processes them, and outputs an array of items:

Input: INodeExecutionData[]        →  Node  →  Output: INodeExecutionData[][]
[item0, item1, item2]                         [[result0, result1]]  (single output)
                                              [[trueItems], [falseItems]]  (two outputs)

INodeExecutionData Structure

interface INodeExecutionData {
    json: IDataObject;                    // REQUIRED - main data payload
    binary?: IBinaryKeyData;              // Optional file/binary data
    error?: NodeApiError | NodeOperationError;  // Error info if item errored
    pairedItem?: IPairedItemData | IPairedItemData[] | number;  // Item linking
    metadata?: {
        subExecution: RelatedExecution;   // Sub-workflow execution reference
    };
}
  • json is the ONLY required field -- it contains the item's data as key-value pairs
  • binary holds file data keyed by property name (e.g., "data", "attachment")
  • pairedItem links output items back to their source input items
  • error carries error details when an item fails processing

execute() Return Type

The return type INodeExecutionData[][] is a 2D array:

  • First dimension: output index (output 0, output 1, etc.)
  • Second dimension: items for that output
// Single output node (most common):
return [returnData];  // returnData is INodeExecutionData[]

// Two-output node (e.g., IF node):
return [trueItems, falseItems];

// Three-output node (e.g., Switch):
return [output0Items, output1Items, output2Items];

Binary Data

IBinaryData Structure

interface IBinaryData {
    data: string;          // Base64 encoded binary data (or reference ID)
    mimeType: string;      // MIME type (e.g., "image/png", "application/pdf")
    fileType?: BinaryFileType;  // 'text' | 'json' | 'image' | 'audio' | 'video' | 'pdf' | 'html'
    fileName?: string;
    fileExtension?: string;
    fileSize?: string;
    id?: string;           // Reference ID for filesystem-stored binary
}

IBinaryKeyData

Binary data on an item is stored as a keyed dictionary:

interface IBinaryKeyData {
    [key: string]: IBinaryData;  // e.g., { "data": {...}, "attachment": {...} }
}

ALWAYS access binary data through the key name: item.binary?.data or item.binary?.attachment.

Binary Helper Methods (in execute())

MethodPurpose
this.helpers.assertBinaryData(itemIndex, propertyName)Get binary data or throw
this.helpers.getBinaryDataBuffer(itemIndex, propertyName)Get binary as Buffer
this.helpers.detectBinaryEncoding(buffer)Detect text encoding
this.helpers.prepareBinaryData(buffer, fileName?, mimeType?)Create IBinaryData from Buffer

Paired Items

IPairedItemData Structure

interface IPairedItemData {
    item: number;          // Index of the source item in the input
    input?: number;        // Input index (default 0)
    sourceOverwrite?: ISourceData;  // Override source node
}

Setting Paired Items

ALWAYS set pairedItem when creating output items to maintain data lineage:

for (let i = 0; i < items.length; i++) {
    returnData.push({
        json: { /* processed data */ },
        pairedItem: { item: i },  // Links to input item at index i
    });
}

For items that map to multiple source items, use an array:

returnData.push({
    json: { /* aggregated data */ },
    pairedItem: [{ item: 0 }, { item: 1 }, { item: 2 }],
});

Process Modes

Single Process (Default)

  • One Node.js process handles everything: webhooks, triggers, UI, and execution
  • Suitable for low-volume workloads or development

Queue Mode (Production Scaling)

  • Main process: Handles webhooks, triggers, and UI; enqueues execution jobs
  • Worker processes: Dequeue and execute workflows independently
  • Uses BullMQ (Redis-backed) for job queue management
Environment VariablePurpose
EXECUTIONS_MODE=queueEnable queue mode
QUEUE_BULL_REDIS_HOSTRedis host for job queue
QUEUE_BULL_REDIS_PORTRedis port for job queue
QUEUE_WORKER_CONCURRENCYConcurrent executions per worker

Workflow Settings (IWorkflowSettings)

SettingTypePurpose
timezonestringWorkflow timezone (e.g., "Europe/Amsterdam")
errorWorkflowstringWorkflow ID to execute on error
executionTimeoutnumberTimeout in seconds
executionOrder'v0' | 'v1'Node execution order algorithm
saveDataErrorExecutionstringSave policy for failed executions
saveDataSuccessExecutionstringSave policy for successful executions
saveManualExecutionsbooleanWhether to save manual test executions
saveExecutionProgressbooleanSave progress during execution
callerPolicyCallerPolicySub-workflow access control
callerIdsstringAllowed caller workflow IDs

ALWAYS set executionOrder: 'v1' for new workflows -- v0 is legacy and produces non-deterministic execution order.


Expression Data Proxy

During execution, expressions have access to these variables:

VariableTypePurpose
$jsonIDataObjectCurrent item's JSON data
$binaryIBinaryKeyDataCurrent item's binary data
$inputProxyInputCurrent node's input accessor
$input.all()INodeExecutionData[]All input items
$input.first()INodeExecutionDataFirst input item
$input.last()INodeExecutionDataLast input item
$input.itemINodeExecutionDataCurrent input item
$node["Name"]--Access another node's output
$workflow--Workflow metadata
$execution.idstringCurrent execution ID
$execution.mode'test' | 'production'Execution mode
$execution.resumeUrlstringURL to resume waiting executions
$nowDateTimeCurrent DateTime (Luxon)
$todayDateTimeToday's date (Luxon)
$parameterINodeParametersCurrent node's parameters
$positionnumberCurrent item index
$env--Environment variables

$execution.customData

Store and retrieve custom metadata during execution:

$execution.customData.set("orderId", "12345");
$execution.customData.get("orderId");  // "12345"
$execution.customData.setAll({ key1: "val1", key2: "val2" });
$execution.customData.getAll();  // { key1: "val1", key2: "val2" }

Decision Trees

Choosing a Node Type

Need to START a workflow?
├── YES → Is it time-based?
│   ├── YES → Use trigger() with ITriggerFunctions (schedule trigger)
│   └── NO → Does it receive HTTP requests?
│       ├── YES → Use webhook() with IWebhookFunctions
│       └── NO → Does it poll an external service?
│           ├── YES → Use poll() with IPollFunctions (set polling: true)
│           └── NO → Use trigger() with custom event listener
└── NO → Is it a simple REST API wrapper?
    ├── YES → Use declarative node (routing config, no execute())
    └── NO → Use programmatic node with execute()

Choosing Process Mode

How many executions per day?
├── < 1000 → Single process (default)
├── 1000-10000 → Queue mode with 1-2 workers
└── > 10000 → Queue mode with multiple workers + Redis cluster

Reference Links

Official Sources

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.