Expression Engine
Relevant source files
The following files were used as context for generating this wiki page:
- packages/@n8n/ai-workflow-builder.ee/src/code-builder/prompts/index.ts
- packages/@n8n/instance-ai/skills/workflow-builder/SKILL.md
- packages/@n8n/workflow-sdk/src/prompts/best-practices/guides/data-analysis.ts
- packages/@n8n/workflow-sdk/src/prompts/best-practices/guides/web-app.ts
- packages/nodes-base/nodes/HtmlExtract/test/workflow.dotNotation.json
The Expression Engine is a core component within the n8n ecosystem designed to handle dynamic data manipulation and parameter assignment at runtime. It allows developers and users to write JavaScript-based logic, wrapped in a specific syntax, to reference data from previous nodes, perform calculations, and transform JSON objects. The engine operates within a sandboxed environment to ensure security while providing access to a wide range of internal variables and utility functions.
In the context of the Workflow SDK, expressions are primarily defined using the expr() helper, which indicates to the system that the enclosed string should be treated as a dynamic value rather than a literal string. This is essential for workflows that must respond to varying input data across different execution cycles.
Core Syntax and Implementation
Expressions in n8n are distinguished by the use of double curly brackets {{ }}. When using the JavaScript SDK, these are wrapped in the expr() function.
Basic Usage Rules
- Wrapping: All dynamic content must be inside
{{ }}tags. - Quotes: Use single or double quotes within
expr(); backtick template literals are not supported for defining the expression itself. - Multiline Expressions: For complex or multiline logic, use standard string concatenation within the
expr()call.
Sources: packages/@n8n/ai-workflow-builder.ee/src/code-builder/prompts/index.ts:474-477, packages/@n8n/instance-ai/skills/workflow-builder/SKILL.md:470-474
Data Flow Representation
The following diagram illustrates how data flows from a source node into an expression-enabled parameter of a downstream node.
This diagram shows the transition of raw JSON data through the Expression Engine to become a resolved parameter value.
Sources: packages/nodes-base/nodes/HtmlExtract/test/workflow.dotNotation.json:115-118, packages/@n8n/instance-ai/skills/workflow-builder/SKILL.md:461
Global Variables and Scope
The Expression Engine provides several built-in variables that allow access to the execution context. These variables are scoped to the current item being processed.
Available Variables
| Variable | Description |
|---|---|
$json | Refers to the JSON data of the current item from the immediate predecessor node. |
$('NodeName') | Allows access to the output of a specific upstream node, paired with the current item. |
$now / $today | Accesses Luxon-based date and time helpers for temporal logic. |
$input.all() | Accesses an array of all input items for the current node. |
$itemIndex | The zero-based index of the current item in the input array. |
$execution.mode | Identifies how the workflow was triggered (e.g., manual, production). |
Sources: packages/@n8n/instance-ai/skills/workflow-builder/SKILL.md:461-468
Explicit Referencing with nodeJson
In scenarios where $json might be ambiguous—such as within AI Agent subnodes or after fan-in nodes (Merge, Switch)—the nodeJson(node, 'path') helper is used to create explicit references to a specific node's output.
// Example of explicit reference
sessionKey: nodeJson(telegramTrigger, 'message.chat.id')
Sources: packages/@n8n/instance-ai/skills/workflow-builder/SKILL.md:476-482
Data Transformation and Best Practices
The Expression Engine handles data types strictly, which necessitates careful management of input values to avoid logic errors.
Type Mismatches
A common pitfall occurs when comparing different data types. For example, the string comparison "5" > "10" evaluates to true lexicographically, whereas a numeric comparison is required. Developers are encouraged to:
- Convert data types early using
Number()orparseInt(). - Enable "Convert types where required" on conditional nodes like IF or Filter.
- Validate data types early in the workflow to prevent downstream failures.
Sources: packages/@n8n/workflow-sdk/src/prompts/best-practices/guides/data-analysis.ts:168-176
Workflow Logic Execution
The engine follows the standard n8n execution model where nodes run once for every input item. If a node receives 10 items, the expressions within that node will be evaluated 10 times.
The sequence diagram demonstrates the per-item evaluation logic of the engine.
Sources: packages/@n8n/instance-ai/skills/workflow-builder/SKILL.md:484-488
Special Use Cases
HTML and Web Apps
When serving HTML via webhooks, bare expressions like {{ $json... }} inside string parameters may not evaluate as expected. For complex HTML generation, the recommended pattern is to use a Code node to replace placeholders (e.g., __DATA_PLACEHOLDER__) with runtime data, often base64-encoded to ensure safety.
Sources: packages/@n8n/workflow-sdk/src/prompts/best-practices/guides/web-app.ts:25-32
Regex in Expressions
Native regex operations can be performed within expressions without requiring a dedicated Code node. This includes testing patterns, extracting matches, and replacing text.
- Test:
{{ $json.field.match(/pattern/) }} - Extract: Using
Edit Fieldswith regex expressions.
Sources: packages/@n8n/ai-workflow-builder.ee/src/code-builder/prompts/index.ts:515-520
Summary of Usage Constraints
| Constraint | Rule |
|---|---|
| No Backticks | Do not use backticks inside expr() for template literals. |
No first() for multi-item | Avoid $('Node').first() for per-item data as it always reads index 0. |
| Single Predecessor | $json only provides data from the immediate previous node. |
| Placeholder Safety | Do not wrap placeholder() helpers in expr() calls. |
Sources: packages/@n8n/ai-workflow-builder.ee/src/code-builder/prompts/index.ts:474-482, packages/@n8n/instance-ai/skills/workflow-builder/SKILL.md:484-488