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

# Flow Structure

> The shape of a Flow document: inputs, calls, and the bindings between them.

A **Flow** is an immutable JSON document describing a multi-step DeFi operation. Every Flow has three parts: a version header, declared **inputs**, and an ordered list of op **calls** (also called *nodes*).

All `name` and `id` fields in a Flow (input names, node ids, the flow's own `id`) are **user-defined**. You pick them when authoring; the compiler uses them only to correlate outputs with downstream bindings. Pick short, meaningful names like `amountIn`, `swap`, `zap`. They're what you read when debugging the wire-format JSON.

## Top-level shape

```json theme={"system"}
{
  "version": 1,
  "id": "swap-and-zap-weth-to-aave",
  "chainId": 1,
  "inputs": [ /* FlowInput[] */ ],
  "nodes":  [ /* Call[] */ ]
}
```

The `chainId` is the EVM chain every call in this Flow targets; inputs whose resource is on a different chain are rejected at build time. `inputs` declares the named values the flow consumes; `nodes` is the ordered list of op calls. For the field-by-field reference of every key, see [Flow Schema](/composer/composer-api/reference/flow-wire-format).

## Inputs

Each input is either a **resource input** (a token, with linear consumption) or a **handle input** (a typed scalar like `uint256` or `address`, copy-mode).

Resource inputs carry a balance through the flow. By default exactly one downstream call consumes them. A copy-mode binding can read a resource without consuming it — `core.approve`, for example, references a resource to approve a spender while leaving the balance available for a later consuming binding. A copy-mode read can coexist with one consuming binding for the same resource. The op manifest's port metadata determines which binding consumes and which only reads.

Handle inputs are non-linear: a `uint256` representing a deadline or slippage tolerance can be wired into every op that needs it.

## Calls (nodes)

A `Call` is a single op invocation. The order of `nodes` is the order the compiler lowers them. Each call has a user-defined `id` (referenced by downstream calls as `<id>.<port>`), an `op` name from the manifest, a `bind` map wiring its input ports to refs or literal values, op-specific `config`, and optional `guards` enforcing invariants.

See [References](/composer/composer-api/concepts/ref-grammar) for the ref grammar and [Guards](/composer/composer-api/concepts/simulation-and-guards) for what guards do.

## Ports and handles

Ops declare typed input and output **ports** in the manifest. Each port has a **type** (resource or handle), a **mode** for resource ports (consuming vs read-only), and an **availability** (input vs output). The SDK hands you **handles** for those ports (`builder.inputs.amountIn`, or the object returned by a previous op call) and converts them to wire-format `$ref` strings when it serialises the Flow. The validator rejects bindings whose handle type or mode doesn't match the port.

See [References](/composer/composer-api/concepts/ref-grammar) for scope rules, reserved prefixes, and handle-to-ref conversion.

## Putting it together

The `swap-and-zap` quickstart produces a Flow that, after `builder.build()`, looks roughly like:

```json theme={"system"}
{
  "version": 1,
  "id": "swap-and-zap-weth-to-aave",
  "chainId": 1,
  "inputs": [
    {
      "name": "amountIn",
      "resource": { "kind": "erc20", "token": "0xC02a…Cc2", "chainId": 1 }
    }
  ],
  "nodes": [
    {
      "id": "swap",
      "op": "lifi.swap",
      "bind":   { "amountIn": { "$ref": "input.amountIn" } },
      "config": { "resourceOut": { "kind": "erc20", "token": "0xA0b8…eB48", "chainId": 1 }, "slippage": 0.03 }
    },
    {
      "id": "zap",
      "op": "lifi.zap",
      "bind":   { "amountIn": { "$ref": "swap.amountOut" } },
      "config": { "resourceOut": { "kind": "erc20", "token": "0x98C2…6F5c", "chainId": 1 } },
      "guards": [ { "kind": "slippage", "port": "amountOut", "bps": 100 } ]
    }
  ]
}
```

> Inputs and node bindings carry **resources** (token balances) and **handles** (typed scalars). The next page, [Resource Model](/composer/composer-api/concepts/resources-and-ports), covers how those behave at runtime.

## See also

* [Flow Schema](/composer/composer-api/reference/flow-wire-format) — field-by-field reference of every key.
* [Resource Model](/composer/composer-api/concepts/resources-and-ports) — how resources and handles behave at runtime.
* [References](/composer/composer-api/concepts/ref-grammar) — how `input.*`, `context.*`, and `<nodeId>.<port>` refs resolve.
* [Execution Model](/composer/composer-api/concepts/execution-model) — how a Flow becomes calldata.
