---
title: "Merge"
description: "Combine two lists via append, zip by position, join by field, or cartesian product."
icon: "code-merge"
---

The **Merge** step takes two JSON arrays and combines them into one. Use it to join customer records with their order history, concatenate results from two API calls, pair items by position, or generate every possible combination of two lists.

Four merge modes cover the most common data combination patterns — from a simple concatenation to a full relational join.

---

## Configuration

<Steps>
  <Step title="Input A">
    An expression resolving to the first JSON array — for example, `{{Steps.Fetch_Customers.Output.Body.data}}`.
  </Step>
  <Step title="Input B">
    An expression resolving to the second JSON array — for example, `{{Steps.Fetch_Orders.Output.Body.data}}`.
  </Step>
  <Step title="Mode">
    The merge strategy. See the detailed breakdown below.
  </Step>
  <Step title="Field A / Field B (Merge by Field only)">
    When using **Merge by Field** mode, specify the field name in each array to match on. Items are joined where `A[fieldA]` equals `B[fieldB]`.
  </Step>
</Steps>

---

## Merge modes

<Tabs>
  <Tab title="Append">
    Concatenates the two arrays end-to-end. All items from A appear first, followed by all items from B.

    ```json
    A: [{ "id": 1 }, { "id": 2 }]
    B: [{ "id": 3 }, { "id": 4 }]

    Result: [{ "id": 1 }, { "id": 2 }, { "id": 3 }, { "id": 4 }]
    ```

    **Result size:** `A.length + B.length`

    **Use when:** You have two result sets of the same type and want a single combined list — for example, merging products from two different API calls.
  </Tab>

  <Tab title="Merge by Position">
    Pairs items by their index and merges their properties. Item 0 in A merges with item 0 in B, item 1 with item 1, and so on. If the arrays have different lengths, the result stops at the shorter one.

    When two items are merged, all properties from A are kept, and all properties from B are added. If both items have the same property name, **B wins** (B's value overwrites A's).

    ```json
    A: [{ "name": "Alice", "role": "dev" }, { "name": "Bob", "role": "pm" }]
    B: [{ "score": 95 }, { "score": 82 }]

    Result: [
      { "name": "Alice", "role": "dev", "score": 95 },
      { "name": "Bob", "role": "pm", "score": 82 }
    ]
    ```

    **Result size:** `min(A.length, B.length)`

    **Use when:** Both arrays are aligned by position — for example, a list of employees and a corresponding list of evaluation scores in the same order.
  </Tab>

  <Tab title="Merge by Field">
    Joins items where a field in A matches a field in B — similar to a SQL `JOIN`. For each match, the two items are merged (B's properties overwrite A's on conflict). Unmatched items are excluded.

    Requires **Field A** and **Field B** to be specified.

    ```json
    A: [{ "userId": 1, "name": "Alice" }, { "userId": 2, "name": "Bob" }]
    B: [{ "id": 1, "department": "Engineering" }, { "id": 3, "department": "Sales" }]

    Field A: "userId"
    Field B: "id"

    Result: [
      { "userId": 1, "name": "Alice", "id": 1, "department": "Engineering" }
    ]
    ```

    - Alice matched: `userId: 1` equals `id: 1`
    - Bob excluded: no item in B has `id: 2`
    - The Sales item excluded: no item in A has `userId: 3`

    **Result size:** Number of matched pairs (can be more than either input if one-to-many matches occur)

    **Use when:** You need to enrich one dataset with fields from another using a shared key — for example, joining customers with their orders by customer ID.
  </Tab>

  <Tab title="Multiplex">
    Generates the **cartesian product** — every item in A is merged with every item in B. This creates all possible combinations.

    ```json
    A: [{ "size": "S" }, { "size": "M" }]
    B: [{ "color": "red" }, { "color": "blue" }]

    Result: [
      { "size": "S", "color": "red" },
      { "size": "S", "color": "blue" },
      { "size": "M", "color": "red" },
      { "size": "M", "color": "blue" }
    ]
    ```

    **Result size:** `A.length × B.length`

    **Use when:** You need every combination of two dimensions — for example, generating product variants from a list of sizes and a list of colors.

    <Warning>
      Multiplex can produce very large outputs. An input of 100 × 100 items creates 10,000 results. Be mindful of downstream token limits.
    </Warning>
  </Tab>
</Tabs>

---

## Property conflicts

When two objects are merged (in all modes except Append), properties from **Input B override Input A** if both have the same key:

```json
A item: { "name": "Alice", "status": "active" }
B item: { "status": "vip", "score": 95 }

Merged: { "name": "Alice", "status": "vip", "score": 95 }
```

The merge is **shallow** — only top-level properties are combined. Nested objects are replaced entirely, not recursively merged.

---

## Output

The step returns a **JSON array** containing the merged items.

```
{{Steps.Merge.Value}}  →  [ ...merged items... ]
```

---

## Use case: enrich support tickets with customer data

A customer support agent needs to display recent tickets alongside the customer's account details. Tickets come from one API and customer profiles from another. They share a `customerId` field.

**Agent flow:**
```
Input → Fetch Tickets (HTTP) ─┐
                               ├→ Merge → Format Response (AI Model)
Input → Fetch Customers (HTTP) ┘
```

**Merge configuration:**

| Setting | Value |
|---|---|
| Input A | `{{Steps.Fetch_Tickets.Output.Body.data.tickets}}` |
| Input B | `{{Steps.Fetch_Customers.Output.Body.data.customers}}` |
| Mode | **Merge by Field** |
| Field A | `customerId` |
| Field B | `id` |

**What happens at runtime:**

```json
// Input A — tickets
[
  { "ticketId": "T-101", "customerId": "C-1", "subject": "Login issue", "priority": "high" },
  { "ticketId": "T-102", "customerId": "C-2", "subject": "Billing question", "priority": "low" },
  { "ticketId": "T-103", "customerId": "C-9", "subject": "Feature request", "priority": "medium" }
]

// Input B — customers
[
  { "id": "C-1", "name": "Acme Corp", "plan": "Enterprise", "csm": "Jane" },
  { "id": "C-2", "name": "StartupCo", "plan": "Starter", "csm": "Mike" }
]
```

The Merge step returns:
```json
[
  { "ticketId": "T-101", "customerId": "C-1", "subject": "Login issue", "priority": "high",
    "id": "C-1", "name": "Acme Corp", "plan": "Enterprise", "csm": "Jane" },
  { "ticketId": "T-102", "customerId": "C-2", "subject": "Billing question", "priority": "low",
    "id": "C-2", "name": "StartupCo", "plan": "Starter", "csm": "Mike" }
]
```

- T-101 and T-102 are enriched with their customer's name, plan, and CSM.
- T-103 is excluded because customer `C-9` does not exist in the customers list.
- The AI Model step can now draft a response that references both the ticket details and the customer context.

---

## Tips

<Tip>
  Use **Append** followed by a [Sort](/building-and-deploying-agents/agent-basics/sort-step) step when combining results from multiple sources that need to be presented in a unified, ordered list — for example, merging search results from two knowledge bases and sorting by relevance score.
</Tip>

<Tip>
  **Merge by Field** performs a type-safe comparison — a numeric `1` and a string `"1"` are treated as different values. Ensure your join fields use consistent types across both inputs.
</Tip>

<Info>
  If an item in Input A or Input B is not a JSON object (e.g., it is a string or number), the merge returns the Input B value as-is. Object merging only applies when both items are JSON objects.
</Info>
