> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowmaticai.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflows: Building Automation Pipelines in Flowmatic

> A Flowmatic workflow is a named directed graph of nodes and edges that defines your automation pipeline. Learn how to structure and connect nodes.

A **workflow** in Flowmatic is the core building block of your automation. It combines a human-readable name with a directed graph that describes exactly how data moves from a trigger event through processing steps to a final action — such as sending emails. Once defined, a workflow can be run as many times as you need, and each execution is tracked independently as a **run**.

## What Is a Workflow?

At its simplest, a workflow is a JSON object with two top-level properties:

* **`name`** — a human-readable label you assign to the workflow (e.g., `"Monthly Promotions Campaign"`).
* **`graph`** — an object containing a `nodes` array and an `edges` array that together describe the automation pipeline.

```json title="Minimal workflow structure" theme={null}
{
  "name": "My First Workflow",
  "graph": {
    "nodes": [...],
    "edges": [...]
  }
}
```

Every workflow must contain at least one `TRIGGER` node — this is the entry point that kicks off execution when you enqueue a run. From there, nodes are connected in sequence (or in parallel branches) using edges.

***

## Nodes and Edges

### Nodes

Each entry in the `nodes` array represents a single unit of work. A node object always contains:

| Field  | Type   | Description                                                                                                                                 |
| ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`   | string | A unique identifier you choose (e.g., `"trigger"`, `"ds"`, `"ai1"`). This ID is used to reference the node's outputs in template variables. |
| `type` | string | One of `TRIGGER`, `DATA_SOURCE`, `AI`, `FILTER`, or `OUTPUT`.                                                                               |
| `data` | object | Configuration specific to the node type. A `TRIGGER` node uses `{}`.                                                                        |

```json title="Example node definitions" theme={null}
{
  "nodes": [
    { "id": "trigger", "type": "TRIGGER",      "data": {} },
    { "id": "ds",      "type": "DATA_SOURCE",  "data": { "uploadId": "upl_abc123" } },
    { "id": "ai",      "type": "AI",           "data": { "prompt": "...", "output": [...] } },
    { "id": "f",       "type": "FILTER",       "data": { "source": "{{ai.customers}}", "expr": "rating > 4" } },
    { "id": "out",     "type": "OUTPUT",       "data": { "forEach": "{{f.items}}", "to": "{{item.email}}", "subject": "Hello!", "body": "..." } }
  ]
}
```

### Edges

Edges define the **directed connections** between nodes. Each edge object has:

| Field    | Type   | Description                                                                                  |
| -------- | ------ | -------------------------------------------------------------------------------------------- |
| `source` | string | The `id` of the upstream node.                                                               |
| `target` | string | The `id` of the downstream node that receives control (and can access the source's outputs). |

```json title="Example edge definitions" theme={null}
{
  "edges": [
    { "source": "trigger", "target": "ds" },
    { "source": "ds",      "target": "ai" },
    { "source": "ai",      "target": "f"  },
    { "source": "f",       "target": "out" }
  ]
}
```

Edges are **directional** — data always flows from `source` to `target`. A node may have multiple outgoing edges (fan-out) or multiple incoming edges (fan-in), enabling parallel branches and merge patterns.

<Note>
  Flowmatic executes nodes in topological order. A node will not begin executing until all of its upstream dependencies have completed successfully.
</Note>

***

## How Data Flows Through the Graph

When a run starts, Flowmatic walks the graph from the `TRIGGER` node and executes each subsequent node in dependency order. Each node type produces a well-defined set of **output fields** that downstream nodes can reference.

For example:

1. A `DATA_SOURCE` node reads a CSV and exposes a `rows` array.
2. An `AI` node receives those rows, processes them with an LLM, and exposes custom named fields (e.g., `customers`, `messageBody`).
3. A `FILTER` node filters the AI output and exposes a filtered `items` array.
4. An `OUTPUT` node iterates `items` and sends one email per row.

The mechanism that connects these steps is the **template variable system**.

***

## Template Variables

Template variables let you embed dynamic values from upstream nodes directly into a downstream node's configuration. They use double-curly-brace syntax: `{{nodeId.outputField}}`.

### Referencing Upstream Node Outputs

Use `{{nodeId.outputField}}` anywhere in a node's `data` object to inject the value that `nodeId` produced for `outputField`:

```json title="Referencing a DATA_SOURCE output in an AI prompt" theme={null}
{
  "id": "ai",
  "type": "AI",
  "data": {
    "prompt": "Given these customer rows: {{ds.rows}}, identify high-value customers and return their name, email, and rating.",
    "output": [
      { "name": "customers", "type": "array" }
    ]
  }
}
```

Here, `ds` is the `id` of the `DATA_SOURCE` node and `rows` is the field it outputs. At runtime, Flowmatic substitutes the actual array before passing the prompt to the LLM.

### The `{{item.*}}` Variable Inside `forEach` Loops

The `OUTPUT` node's `forEach` field tells Flowmatic to iterate over an array and send one action per element. Inside the `to`, `subject`, and `body` fields, you use `{{item.fieldName}}` to reference a property of the **current iteration's element**:

```json title="OUTPUT node with item variables" theme={null}
{
  "id": "out",
  "type": "OUTPUT",
  "data": {
    "forEach": "{{f.items}}",
    "to":      "{{item.email}}",
    "subject": "We have a deal for you, {{item.name}}!",
    "body":    "Hi {{item.name}},\n\nBased on your rating of {{item.rating}}, we'd like to offer you exclusive access.\n\nThanks,\nThe Team"
  }
}
```

<Tip>
  Node `id` values you choose become the namespace for that node's template variables. Keep them short and descriptive (e.g., `ds`, `ai`, `f`, `out`) to make your template expressions readable.
</Tip>

***

## Complete Workflow Example

Below is a full workflow that loads customer data from a CSV, uses AI to identify high-value customers, filters for those with a rating above 4, and sends each a personalized email.

```json title="Complete workflow definition" theme={null}
{
  "name": "High-Value Customer Outreach",
  "graph": {
    "nodes": [
      {
        "id": "trigger",
        "type": "TRIGGER",
        "data": {}
      },
      {
        "id": "ds",
        "type": "DATA_SOURCE",
        "data": {
          "uploadId": "upl_abc123"
        }
      },
      {
        "id": "ai",
        "type": "AI",
        "data": {
          "prompt": "Analyze the following customer rows: {{ds.rows}}. For each customer, extract their name, email, rating, and generate a short personalized message in a field called messageBody.",
          "output": [
            { "name": "customers", "type": "array" },
            { "name": "messageBody", "type": "string" }
          ]
        }
      },
      {
        "id": "f",
        "type": "FILTER",
        "data": {
          "source": "{{ai.customers}}",
          "expr": "rating > 4"
        }
      },
      {
        "id": "out",
        "type": "OUTPUT",
        "data": {
          "forEach": "{{f.items}}",
          "to":      "{{item.email}}",
          "subject": "A special message for {{item.name}}",
          "body":    "Hi {{item.name}},\n\n{{item.messageBody}}\n\nBest,\nThe Team"
        }
      }
    ],
    "edges": [
      { "source": "trigger", "target": "ds"  },
      { "source": "ds",      "target": "ai"  },
      { "source": "ai",      "target": "f"   },
      { "source": "f",       "target": "out" }
    ]
  }
}
```

***

## Workflow Lifecycle

Working with a workflow follows a straightforward three-phase pattern:

<Steps>
  <Step title="Create the workflow">
    Send a `POST /api/workflows` request with your `name` and `graph`. Flowmatic validates the graph structure and returns a `workflowId`. The workflow is stored but not yet executed.
  </Step>

  <Step title="Enqueue a run">
    Send a `POST /api/workflows/:workflowId/run` request to start an execution. Flowmatic immediately returns a `202 Accepted` with a `runId` and an initial status of `PENDING`. Execution happens asynchronously in the background.
  </Step>

  <Step title="Monitor the run">
    Poll `GET /api/workflows/runs/:runId` to track progress. The response includes the overall run status (`PENDING`, `RUNNING`, `SUCCESS`, or `FAILED`) as well as a per-node status breakdown so you can pinpoint exactly where things stand.
  </Step>
</Steps>

### Multiple Runs Per Workflow

A single workflow definition can be run any number of times. Each run is independent — it gets its own `runId` and its own status lifecycle. This makes it easy to:

* **Re-run** a workflow after fixing upstream data.
* **Batch test** a workflow with different CSV uploads by swapping the `DATA_SOURCE` node's `uploadId`.
* **Schedule recurring** executions by enqueuing a new run on a cron schedule.

<Info>
  Runs for the same workflow are queued and executed one at a time. If you enqueue a second run while the first is still `RUNNING`, the second will remain `PENDING` until the first completes. See the [Runs](/concepts/runs) guide for details.
</Info>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Node Types" icon="circle-nodes" href="/concepts/nodes">
    Deep-dive into every node type — what each one does, its configuration fields, and what it outputs.
  </Card>

  <Card title="Runs" icon="circle-play" href="/concepts/runs">
    Learn how asynchronous runs work, how to poll for status, and how to handle failures.
  </Card>
</CardGroup>
