Skip to main content
The Transform node is the Swiss Army knife of your flow. It operates in four distinct modes — each designed for a different data manipulation pattern. Whether you need to reshape a payload, loop over a list, collect results from parallel branches, or pause execution, the Transform node handles it.

Modes

Reshape and map data from one structure to another.

Message Mode

Message is the most common mode. It takes data from previous nodes and reshapes it into a new structure. Use it to extract fields, rename keys, combine data from multiple sources, build API payloads, or set default values.

How It Works

You define a JSON mapping where each key is the output field name, and each value is either a static value or a template expression that pulls data from upstream nodes.

Configuration

SettingDescription
Output MappingA JSON object defining the transformed output. Values support {{template}} syntax.

Example

A previous Request node (ID 1, label “Fetch User”) returned:
{
  "body": {
    "first_name": "Jane",
    "last_name": "Doe",
    "contact": { "email": "jane@acme.com" },
    "metadata": { "tier": "enterprise" }
  }
}
Configure the Transform in Message mode:
{
  "full_name": "{{1_Fetch User.body.first_name}} {{1_Fetch User.body.last_name}}",
  "email": "{{1_Fetch User.body.contact.email}}",
  "tier": "{{1_Fetch User.body.metadata.tier}}",
  "source": "api_sync"
}
This outputs a clean, flat object:
{
  "full_name": "Jane Doe",
  "email": "jane@acme.com",
  "tier": "enterprise",
  "source": "api_sync"
}

Common Patterns

Map an external API’s naming convention to your internal format:
{
  "customer_name": "{{1_API.body.customerName}}",
  "customer_email": "{{1_API.body.emailAddress}}",
  "signup_date": "{{1_API.body.createdAt}}"
}
Pull fields from different upstream nodes into a single object:
{
  "user": "{{1_Lookup User.body.name}}",
  "order_total": "{{2_Fetch Order.body.total}}",
  "status": "{{3_Check Status.body.result}}"
}
Prepare a structured body for a downstream Request node:
{
  "to": "{{1_Form.form_data.email}}",
  "subject": "Welcome, {{1_Form.form_data.name}}!",
  "template": "onboarding_v2",
  "variables": {
    "name": "{{1_Form.form_data.name}}",
    "company": "{{1_Form.form_data.company}}"
  }
}
Mix dynamic and static values:
{
  "name": "{{1_Input.body.name}}",
  "role": "member",
  "active": true,
  "region": "us-east-1"
}
Use a Transform in Message mode before a Request node to cleanly separate “what data do I need” from “where do I send it.” This makes your flows easier to debug and modify.

Iterate Mode

Iterate takes a list and runs every downstream node once for each item in that list. It turns a single flow execution into a loop, processing each element individually.

How It Works

You point the Transform at a list from a previous node. For each item in that list, the nodes connected after the Transform execute with that single item as their input. The flow effectively “fans out” — if the list has 50 items, the downstream path runs 50 times.

Configuration

SettingDescription
Source ListA template expression pointing to the array to iterate over (e.g., {{1_Request.body.users}})

Example

A Request node fetches a list of 3 users:
{
  "body": {
    "users": [
      { "name": "Alice", "email": "alice@acme.com" },
      { "name": "Bob", "email": "bob@acme.com" },
      { "name": "Charlie", "email": "charlie@acme.com" }
    ]
  }
}
Set the Transform to Iterate mode with source list {{1_Request.body.users}}. The downstream nodes run 3 times — once with Alice’s data, once with Bob’s, once with Charlie’s. Each iteration receives the current item as its input.

Use Cases

  • Sending a personalized email to each contact in a list
  • Creating a ticket for every failed check in a batch
  • Writing each record from an API response to a data table
  • Making an individual API call per item (e.g., enriching each lead)
Iterations run sequentially by default. For large lists, keep downstream operations lightweight or use the failure path to handle individual item errors without stopping the entire loop.

Gather Mode

Gather is the counterpart to Iterate. After a fan-out, Gather collects all the individual results back into a single list so the flow can continue with the complete set.

How It Works

Place a Gather Transform after a section of your flow that was fanned out by an Iterate. The Gather waits for all iterations to complete, then combines their outputs into an array. Downstream nodes receive the full collected result.

Configuration

SettingDescription
SourceThe node whose iterated outputs should be collected

Example

Continuing the example above:
  1. Iterate fans out over 3 users
  2. For each user, a Request node calls an enrichment API and returns additional data
  3. Gather collects all 3 enrichment results into a single list
The Gather output:
[
  { "name": "Alice", "company": "Acme Corp", "title": "Engineer" },
  { "name": "Bob", "company": "Acme Corp", "title": "Designer" },
  { "name": "Charlie", "company": "Acme Corp", "title": "PM" }
]
Now a downstream Table node can write all 3 enriched records at once, or a Transform in Message mode can summarize the batch.

The Iterate → Gather Pattern

This is one of the most powerful patterns in Zygo:
Fetch list → Iterate → Process each item → Gather → Continue with results
1

Fetch

A Request node retrieves a list of items from an API.
2

Iterate

A Transform in Iterate mode fans out over the list.
3

Process

Each item flows through one or more nodes — enrichment, validation, transformation.
4

Gather

A Transform in Gather mode collects all processed items back into a single list.
5

Continue

The flow continues with the complete set — write to a table, send a summary, or pass to another system.
You can nest Iterate/Gather pairs for multi-level looping — for example, iterating over departments, then iterating over employees within each department.

Wait Mode

Wait pauses the flow for a specified duration before continuing to the next node. Use it to add intentional delays — rate limit compliance, polling intervals, or giving an external system time to process before you check the result.

Configuration

SettingDescription
DurationHow long to pause, in seconds

Use Cases

You’re calling an external API inside an Iterate loop that has a rate limit of 10 requests per second. Add a Wait node with a 1-second delay between each call to stay under the limit.
You trigger an async job on an external system, then need to check if it’s done. Add a Wait before the status-check Request to give the job time to complete:
  1. Request — trigger the job
  2. Wait — pause for 30 seconds
  3. Request — check the job status
  4. Condition — is it done? If not, loop back to Wait
Send a sequence of messages with delays between them — a welcome email now, a follow-up in 5 minutes, and a tips email in an hour.
After a failed request, wait before retrying. Chain multiple Wait + Request pairs with increasing durations for exponential backoff.
Wait pauses the flow execution in the background job queue. Very long wait durations (hours) tie up a worker — for long delays, consider using a scheduled flow instead of a Wait node.

Output

Regardless of mode, downstream nodes reference the Transform’s output using the standard template syntax:
{{2_Transform.field_name}}
ModeOutput
MessageThe JSON object you defined in the mapping
IterateThe current item from the list (available to nodes within the loop)
GatherAn array containing all collected results
WaitPasses through the input data unchanged

Choosing the Right Mode

I need to…Use
Reshape or restructure dataMessage
Process each item in a list individuallyIterate
Collect iterated results back into a listGather
Pause before the next stepWait
Rename fields or build a payloadMessage
Send an email to every user in a listIterate
Summarize results after a loopGather
Respect an API’s rate limitWait