# Flows

Flows are CairnCMS's automation primitive. Each flow runs a sequence of operations in response to a trigger, with the ability to read or write data, send email and notifications, transform values, branch on conditions, call external services, and chain to other flows.

Most use cases that would otherwise require a separate background worker, cron daemon, or external orchestrator can be expressed as a flow. Everything in a flow runs server-side; nothing runs in the user's browser.

## What is a flow?

Each flow has three parts:

- a **trigger** that defines when the flow runs
- one or more **operations** that do the work
- a **data chain** that operations read and write as the flow progresses

Flows are configured under **Settings > Flows** in the app.

## Triggers

A trigger is the entry point for a flow. CairnCMS supports five trigger types:

- **Event hook** — fires when something happens in the platform (item created, item updated, user logged in, and so on). Filter triggers can transform or veto the event; Action triggers run after the event is committed.
- **Webhook** — fires on an incoming HTTP request to a flow-specific URL.
- **Schedule (cron)** — fires on a cron schedule.
- **Another flow** — fires from a Trigger Flow operation in another flow. This is how flows compose.
- **Manual** — fires when a user clicks a button in the app on a collection or item page.

The full list of trigger types and their configuration is on the [Triggers](/docs/guides/flows/triggers/) page.

## Operations

An operation is one step inside a flow. Operations cover three broad jobs:

- **read data** from CairnCMS or an external service
- **process data** by transforming, validating, or branching on it
- **write data** back to CairnCMS or send it to an external service

Built-in operations include item CRUD, condition branching, sending email and notifications, calling external URLs, sleeping, transforming payloads, running custom scripts, and triggering other flows. Custom operations can also be added through the extension system.

The full list of operations and their configuration is on the [Operations](/docs/guides/flows/operations/) page.

## The data chain

Every flow runs against a single JSON object called the data chain. As each operation finishes, it appends its result onto this object under its operation key. Subsequent operations can then reference earlier results.

Four keys are present from the start of every flow:

- `$trigger` — data generated by the trigger (the event payload, the webhook body, the manual selection, and so on)
- `$accountability` — context about who or what initiated the flow (user, role, IP address, user agent)
- `$env` — environment variables exposed to flows through the `FLOWS_ENV_ALLOW_LIST` config option
- `$last` — the result of the most recently completed operation

Each operation also writes under its own key, named after the operation:

```json
{
  "$trigger": { },
  "$accountability": { },
  "$env": { },
  "$last": { },
  "fetch_user": { "id": "abc", "name": "Alex" },
  "send_email": null
}
```

`null` is appended for operations that complete without producing a value (sending email, logging to console, sleeping, and so on).

## Data chain variables

Operations reference earlier values using double-mustache syntax:

```json
{
  "to": "{{ fetch_user.email }}",
  "subject": "Welcome, {{ $trigger.payload.name }}"
}
```

Dot notation traverses nested objects. Array indexing also works: `{{ items[0].title }}`.

The mustache syntax substitutes values; it does not evaluate expressions. For computation, use the **Run Script** operation.

Most configuration fields support data chain variables, including dropdowns, toggles, and other inputs once you enable the raw editor on that field.

## Control flow

Operations can succeed or fail. Each operation has two outgoing paths:

- the **success path** runs the next operation if this one succeeded
- the **failure path** runs a different operation if this one failed

This lets a flow branch on the outcome of a single operation. Failures do not automatically stop a flow . They redirect to the failure path. A flow ends only when it reaches an operation with no path defined for its outcome.

The **Condition** operation is the most common way to branch deliberately: it always runs, evaluates a filter rule against the data chain, and routes execution to the success or failure path based on the result.

## Logs

Every flow with logging enabled records each run. Logs are reached from the section on a flow's page in the app. Each log shows:

- the trigger options and payload
- the accountability context
- each operation's options and the value it appended

`$last` is not stored separately in logs. It is always equivalent to the last operation's payload.

Logs are written to the database. Long-running deployments with high-frequency flows should periodically prune log records.

## Creating a flow

The basic workflow is the same regardless of trigger type:

1. Go to **Settings > Flows** and create a new flow.
2. Choose a trigger and configure it.
3. Add operations, connecting each one to the success or failure path of the previous operation.
4. Save and test.

Each operation is added by clicking the success or failure connector on the previous operation. Operations can also be duplicated, copied between flows, repositioned, and unlinked or relinked through the flow editor.

## Where to go next

The next two pages cover the full reference of trigger types and operations:

- [Triggers](/docs/guides/flows/triggers/) covers each trigger type and its configuration.
- [Operations](/docs/guides/flows/operations/) covers each built-in operation, what it does, and what it appends to the data chain.

For sending and receiving HTTP requests, see the [Webhooks](/docs/guides/flows/webhooks/) page.