Zip
Merge multiple input streams into combined output
The Zip node merges multiple input streams into a single output. Use it to combine data from parallel processing paths or to aggregate results from multiple sources.
Overview
| Property | Value |
|---|---|
| Category | Control |
| Node IDs | ds.zip.batch.in2.success1.error0 (2 inputs)ds.zip.batch.in3.success1.error0 (3 inputs)ds.zip.batch.in4.success1.error0 (4 inputs) |
| Input Ports | 2, 3, or 4 |
| Success Outputs | 1 |
| Error Outputs | 0 |
| Execution Mode | Batch |
Configuration
| Parameter | Type | Required | Description |
|---|---|---|---|
labels | Array of strings | Yes | Labels for each input stream |
Labels
Name each input stream for easy access in downstream nodes:
labels: ["summary", "actionItems"]
Then access as:
{{ json.summary }}
{{ json.actionItems }}
How It Works
Input 1 (summary) ──┐
├─→ [Zip] → { summary: [...], actionItems: [...] }
Input 2 (items) ────┘
The Zip node:
- Waits for data on ALL input ports
- Collects all items from each input stream
- Combines them into a single object with labeled arrays
- Outputs the combined data as a batch
Input Schema
Accepts any data on each input port. Items are collected into arrays per port.
Output Schema
Combined Output
{
"summary": [
{ "type": "string", "value": "Meeting covered Q1 goals..." }
],
"actionItems": [
{ "task": "Follow up with client", "owner": "John" },
{ "task": "Send proposal", "owner": "Jane" }
]
}
Each input stream becomes a labeled array in the output:
- Label from
labelsconfig → key in output object - All items from that input → array value
Variants
Zip (2 inputs)
Most common—combine two parallel results:
[AI: Summarize] ─────┐
├─→ [Zip 2] → Combined
[AI: Extract Items] ─┘
Zip (3 inputs)
Combine three streams:
[Summary] ──────┐
│
[Action Items] ─┼─→ [Zip 3] → Combined
│
[Sentiment] ────┘
Zip (4 inputs)
Maximum four streams:
[Stream A] ──┐
[Stream B] ──┼─→ [Zip 4] → Combined
[Stream C] ──┤
[Stream D] ──┘
Examples
Basic Example: Combine AI Results
Run two AI analyses in parallel, then combine.
Workflow:
┌─→ [AI: Summarize] ─────┐
[Load Meeting] ──┤ ├─→ [Zip] → [Slack Post]
└─→ [AI: Extract Items] ─┘
Zip Configuration:
- Labels:
["summary", "actionItems"]
Slack Message:
📋 *Meeting Summary*
{{ json.summary[0].value }}
{% if json.actionItems[0].value.size > 0 %}
*Action Items:*
{% for item in json.actionItems[0].value %}
• {{ item }}
{% endfor %}
{% endif %}
Example: Multi-Analysis Pipeline
Combine multiple analyses of the same meeting.
Workflow:
┌─→ [AI: Sentiment] ────┐
│ │
[Load Meeting] ──┼─→ [AI: Key Topics] ───┼─→ [Zip 3] → [Generate Report]
│ │
└─→ [AI: Risk Factors] ─┘
Zip Configuration:
- Labels:
["sentiment", "topics", "risks"]
Access in downstream:
Sentiment: {{ json.sentiment[0].value }}
Topics: {{ json.topics[0].value }}
Risks: {{ json.risks[0].value }}
Example: Combine with Context
Zip original meeting data with analysis.
Workflow:
┌─→ (pass through) ───┐
[Load Meeting] ───┤ ├─→ [Zip] → [Send Report]
└─→ [AI: Analyze] ────┘
Zip Configuration:
- Labels:
["meeting", "analysis"]
Access both:
Meeting: {{ json.meeting[0].title }}
Analysis: {{ json.analysis[0].value }}
Example: Error Path Merging
Merge results from different conditional paths (advanced):
[If: has transcript?]
├─ True ──→ [Analyze Transcript] ───┐
│ ├─→ [Zip] → [Report]
└─ False ─→ [Generate Placeholder] ─┘
Note: This only works if both paths produce output. For conditional flows, consider Broadcast instead.
Best Practices
1. Match Label Count to Inputs
Labels array length must match number of inputs:
- Zip 2 → 2 labels
- Zip 3 → 3 labels
- Zip 4 → 4 labels
2. Use Descriptive Labels
✅ Good:
["meetingSummary", "extractedActionItems"]
❌ Bad:
["input1", "input2"]
3. Handle Single-Item Arrays
Zip collects into arrays, even for single items:
{{ json.summary[0].value }} // Access first (often only) item
4. Consider Timing
Zip waits for ALL inputs:
- If one path is slow, Zip waits
- If one path fails, Zip may not complete
- Design for similar-duration parallel paths
5. Use for True Parallel Processing
Zip is best when both branches should run:
✅ Good use: Two analyses of the same data ❌ Bad use: Conditional paths where only one runs
Common Issues
Zip never outputs
Symptom: Workflow hangs at Zip node
Cause: One or more inputs never receive data
Solutions:
- Verify all upstream paths produce output
- Check conditional logic—does every branch reach Zip?
- Ensure no upstream errors are swallowing data
Array access errors
Symptom: undefined or errors when accessing zipped data
Cause: Forgetting Zip creates arrays
Solution: Always use array index:
{{ json.summary[0].value }} // Correct
{{ json.summary.value }} // Incorrect
Wrong labels
Symptom: Data not accessible by expected name
Cause: Labels don't match input order
Solution: Labels correspond to input ports in order:
- Input port 1 → Label 1
- Input port 2 → Label 2
- etc.
Related Nodes
- Broadcast - Different merging pattern (context + items)
- If - Create parallel branches before Zip
- Select Many - Expand after Zip if needed
Technical Details
Batch Processing
Zip operates in batch mode:
- Waits for ALL inputs to be ready
- Processes all items together
- Outputs a single combined result
Input Buffering
Items arriving at each input are buffered until all inputs have data. This ensures:
- All data is available for combination
- Output contains complete results from all branches
Timing Considerations
If inputs arrive at different times:
- Earlier inputs are buffered
- Zip executes when the last input arrives
- Total time = slowest branch time
Array Structure
Each input stream's items become an array:
{
"label1": [item1, item2, ...], // All items from input 1
"label2": [itemA, itemB, ...] // All items from input 2
}
For per-item processing that produced single items, arrays will have length 1.