Search documentation

Search for pages in the documentation

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

PropertyValue
CategoryControl
Node IDsds.zip.batch.in2.success1.error0 (2 inputs)
ds.zip.batch.in3.success1.error0 (3 inputs)
ds.zip.batch.in4.success1.error0 (4 inputs)
Input Ports2, 3, or 4
Success Outputs1
Error Outputs0
Execution ModeBatch

Configuration

ParameterTypeRequiredDescription
labelsArray of stringsYesLabels for each input stream

Labels

Name each input stream for easy access in downstream nodes:

text
labels: ["summary", "actionItems"]

Then access as:

liquid
{{ json.summary }}
{{ json.actionItems }}

How It Works

text
Input 1 (summary) ──┐
                    ├─→ [Zip] → { summary: [...], actionItems: [...] }
Input 2 (items) ────┘

The Zip node:

  1. Waits for data on ALL input ports
  2. Collects all items from each input stream
  3. Combines them into a single object with labeled arrays
  4. 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

json
{
  "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 labels config → key in output object
  • All items from that input → array value

Variants

Zip (2 inputs)

Most common—combine two parallel results:

text
[AI: Summarize] ─────┐
                     ├─→ [Zip 2] → Combined
[AI: Extract Items] ─┘

Zip (3 inputs)

Combine three streams:

text
[Summary] ──────┐
                │
[Action Items] ─┼─→ [Zip 3] → Combined
                │
[Sentiment] ────┘

Zip (4 inputs)

Maximum four streams:

text
[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:

text
                 ┌─→ [AI: Summarize] ─────┐
[Load Meeting] ──┤                        ├─→ [Zip] → [Slack Post]
                 └─→ [AI: Extract Items] ─┘

Zip Configuration:

  • Labels: ["summary", "actionItems"]

Slack Message:

liquid
📋 *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:

text
                 ┌─→ [AI: Sentiment] ────┐
                 │                       │
[Load Meeting] ──┼─→ [AI: Key Topics] ───┼─→ [Zip 3] → [Generate Report]
                 │                       │
                 └─→ [AI: Risk Factors] ─┘

Zip Configuration:

  • Labels: ["sentiment", "topics", "risks"]

Access in downstream:

liquid
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:

text
                  ┌─→ (pass through) ───┐
[Load Meeting] ───┤                     ├─→ [Zip] → [Send Report]
                  └─→ [AI: Analyze] ────┘

Zip Configuration:

  • Labels: ["meeting", "analysis"]

Access both:

liquid
Meeting: {{ json.meeting[0].title }}
Analysis: {{ json.analysis[0].value }}

Example: Error Path Merging

Merge results from different conditional paths (advanced):

text
[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:

text
["meetingSummary", "extractedActionItems"]

Bad:

text
["input1", "input2"]

3. Handle Single-Item Arrays

Zip collects into arrays, even for single items:

liquid
{{ 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:

  1. Verify all upstream paths produce output
  2. Check conditional logic—does every branch reach Zip?
  3. 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:

liquid
{{ 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.
  • 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:

json
{
  "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.