---
title: "Amazon Bedrock Flows — the visual workflow builder that wires prompts, knowledge bases, agents, and Lambda into a deployable pipeline"
date: 2026-06-10
service: "Amazon Bedrock"
component: "Flows"
tags: [bedrock, flows, prompt-flow, nodes, condition-node, iterator, collector, do-while, lambda-node, knowledge-base-node, agent-node, inline-code, versions, aliases, invoke-flow, async-execution, start-flow-execution, guardrails, prompt-management, pipeline]
source: https://docs.aws.amazon.com/bedrock/latest/userguide/flows.html
verified_on: 2026-06-10
url: https://vanemmerik.ai/aws-ai/2026-06-10.html
---

# AWS Bedrock & AgentCore · Tip of the Day · 2026-06-10

## Amazon Bedrock Flows — the visual workflow builder that wires prompts, knowledge bases, agents, and Lambda into a deployable pipeline

Every Bedrock resource covered in this series so far — Knowledge Bases, Guardrails, AgentCore agents — solves a piece of a problem. **Amazon Bedrock Flows** is the glue layer: a node-based workflow builder that chains those pieces together into an end-to-end pipeline, versions it as an immutable snapshot, and exposes it as a single API endpoint your application can call. You design the graph (drag-and-drop or JSON), Bedrock handles the orchestration, and you ship to production in a few CLI commands.

    aws bedrock-agent create-flow \
      --name "my-rag-flow" \
      --execution-role-arn arn:aws:iam::123456789012:role/MyFlowsRole \
      --definition file://flow-definition.json

≈ 8 min read · Amazon Bedrock · Flows

## 01 · What Flows actually is — and the three-phase lifecycle

A **flow** is a directed graph: a collection of named nodes connected by typed edges (connections). When you call `InvokeFlow`, the input travels through the graph from the single required input node until it reaches one or more output nodes; the response carries the final output. Everything between — model calls, knowledge-base queries, Lambda invocations, branching logic — is invisible to the caller.

The lifecycle has three phases that mirror how Bedrock Agents handles deployments:

**1 · Draft (DRAFT)**  
`CreateFlow` creates a mutable working draft. You can call `UpdateFlow` as many times as you like and then `PrepareFlow` to compile the latest changes into a testable state. InvokeFlow on DRAFT is fine for testing.

**2 · Version**  
`CreateFlowVersion` takes a snapshot of the current DRAFT and assigns an immutable integer version number. Versions never change — they are the production artifact.

**3 · Alias**  
`CreateFlowAlias` creates a named pointer (e.g. `latest`, `prod`, `blue`) that routes invocations to one or more versions via a weighted `routingConfiguration`. Your application calls the alias; you do blue/green or canary by updating alias routing without changing your integration.

---

## 02 · The thirteen node types

Nodes fall into two families. Logic nodes control flow; data nodes do work.

### Logic nodes

| Node | What it does |
|------|-------------|
| **Input** | Entry point. Validates the `content` from `InvokeFlow` and forwards it. Every flow has exactly one. |
| **Output** | Exit point. Extracts from the previous node and returns as `flowOutputEvent.content`. A flow can have multiple output nodes — one per branch. |
| **Condition** | Evaluates relational + logical expressions (`==`, `!=`, `>`, `>=`, `<`, `<=`, `and`, `or`, `not`) over named inputs and sends data down matching branches. Conditions are evaluated in order; first match wins. The `default` condition is the fallback. |
| **Iterator** | Takes an Array input and emits items **serially** (not in parallel). Each item produces a separate response. Outputs: `arrayItem` + `arraySize`. |
| **Collector** | Receives iterated items and re-assembles them into an Array. Pair with Iterator for fan-out / fan-in. |
| **DoWhile** | Runs a sub-graph repeatedly while a boolean condition remains true. Condition is evaluated *after* each pass (do-while semantics). `maxIterations` defaults to 10; always specify it explicitly to avoid surprise exits. |

### Data nodes

| Node | What it does |
|------|-------------|
| **Prompt** | Calls a foundation model. The prompt is either inline (model ID + template + inference params) or referenced from Prompt Management by ARN. Inputs map to template variables; output is `modelCompletion: String`. Guardrails attach here. |
| **Agent** | Invokes a Bedrock Agent alias (`agentAliasArn`). Supports multi-turn: the agent can pause, ask the user for clarification mid-flow, and resume. |
| **KnowledgeBase** | Queries a Bedrock Knowledge Base. With `modelId` → `RetrieveAndGenerate` (returns `outputText: String`). Without `modelId` → `Retrieve` (returns `retrievalResults: Array`). Guardrails only work with `RetrieveAndGenerate`. |
| **Storage (S3)** | Writes content to an S3 bucket. Inputs: `content` + `objectKey`. Output: `s3Uri`. |
| **Retrieval (S3)** | Reads a UTF-8 string from an S3 object key. Output: `s3Content`. |
| **LambdaFunction** | Calls a Lambda function. The input event follows a standard schema (`messageVersion: "1.0"`, `flow.*`, `node.inputs.*`). Output is whatever the Lambda returns. Supports cross-account invocations. |
| **InlineCode** *(preview)* | Executes Python 3 code in an isolated, managed environment with no internet access. The last evaluated expression is returned as output. No external Lambda required. |

---

## 03 · Connections and expressions

There are exactly two connection types:

- **Data connection** (solid gray line in the console) — carries data from an upstream node output to a downstream node input.
- **Conditional connection** (dotted purple line) — carries data from a condition node to a downstream node when that condition evaluates to true.

Every input to a node is configured with an **expression** — a JSONPath-like selector that extracts the relevant slice of the *whole input* (the full data arriving at the node) for that specific input slot. The simplest expression is `$.data`, which selects the entire document. `$.data.genre` digs one level in; `$.data[1]` takes the second item from an array. Amazon Bedrock validates the extracted value against the declared type (`String`, `Number`, `Boolean`, `Object`, `Array`) at runtime and errors if there's a mismatch.

---

## 04 · Versions, aliases, and what DRAFT means

The **DRAFT** version is the only mutable state. When you want to lock down behavior for production:

```python
# Snapshot → version
response = client.create_flow_version(flowIdentifier=flow_id)
flow_version = response["version"]            # e.g., "1"

# Alias → stable invocation endpoint
client.create_flow_alias(
    flowIdentifier=flow_id,
    name="prod",
    routingConfiguration=[{"flowVersion": flow_version}]
)
```

To do a canary rollout, update the alias routing to split traffic:

```python
client.update_flow_alias(
    flowIdentifier=flow_id,
    aliasIdentifier=alias_id,
    routingConfiguration=[
        {"flowVersion": "1", "flowVersionWeight": 0.9},
        {"flowVersion": "2", "flowVersionWeight": 0.1},
    ]
)
```

Your application uses the alias ARN. Promoting v2 to 100% is a single `update_flow_alias` call with no code change on the caller side.

---

## 05 · Synchronous vs asynchronous invocations

**Synchronous — `InvokeFlow`**  
The call blocks until the flow completes or hits the **1-hour hard timeout**. Results stream back as server-sent events on the response body (`flowOutputEvent`, `flowCompletionEvent`, `flowErrorEvent`). Good for interactive, latency-sensitive workloads.

**Asynchronous — `StartFlowExecution`** *(preview)*  
Decouples invocation from execution. Constraints:

| Limit | Value |
|-------|-------|
| Per-node timeout | 5 minutes |
| Total flow runtime | 24 hours |
| Status values | `Running`, `Succeeded`, `Failed`, `TimedOut`, `Aborted` |

The response is an `executionArn`. Poll with `GetFlowExecution` to check status. Retrieve results and per-node debug events with `ListFlowExecutionEvents` (set `eventType=Node` to see intermediate inputs/outputs across all nodes; `eventType=Flow` to see only entry/exit). Amazon Bedrock automatically captures a **snapshot** of the flow definition at execution start (`GetExecutionFlowSnapshot`) — so if you update the flow while an execution is running, the execution continues on the original definition.

---

## 06 · Guardrails, multi-turn, and composing with other Bedrock resources

**Guardrails** attach to Prompt nodes (scans prompt + response) and KnowledgeBase nodes (only when using `RetrieveAndGenerate`, not bare `Retrieve`). Add the `guardrailConfiguration` block to the node:

```json
"guardrailConfiguration": {
  "guardrailIdentifier": "abc123",
  "guardrailVersion": "1"
}
```

**Multi-turn flows** — the `Converse` flow invocation mode lets a caller and an Agent node exchange multiple turns in a single flow session. The Agent node pauses mid-execution, returns a prompt to the user, waits for the response, then continues.

**Composing with Prompt Management** — a Prompt node can reference a versioned prompt by ARN instead of defining the prompt inline. This separates prompt authoring from flow wiring: a prompt engineer owns the prompt, a platform team owns the flow graph, and neither blocks the other.

**Pricing** — Flows itself has no per-request charge. You pay for the underlying resources: model invocations on Prompt and Agent nodes, Knowledge Base queries, Lambda invocations, and S3 reads/writes.

---

## Limits worth knowing

1. **`InvokeFlow` hard timeout is 1 hour.** If your flow touches a slow external API or chains many model calls, budget for latency or switch to `StartFlowExecution`.
2. **Iterator is serial, not parallel.** Items fan out one at a time. For high-volume array processing, consider a Lambda node that does the parallel work internally and returns an aggregated result.
3. **DoWhile `maxIterations` defaults to 10.** If you expect more iterations, set it explicitly — silent exit at the limit is easy to miss in testing.
4. **S3 Retrieval requires UTF-8 strings.** Binary files (PDFs, images) need pre-processing before the Retrieval node can consume them.
5. **Guardrails on KnowledgeBase are RetrieveAndGenerate only.** If you use `Retrieve` (no `modelId`) and want content filtering, add a downstream Prompt node with a guardrail attached.
6. **Inline code node is in preview.** Python 3 only; no internet access; last-line expression returned. Stable behavior may differ at GA.
7. **Two distinct API clients.** Build-time operations (CreateFlow, PrepareFlow, CreateFlowVersion, CreateFlowAlias) use the `bedrock-agent` client. Runtime operations (InvokeFlow, StartFlowExecution) use the `bedrock-agent-runtime` client. Using the wrong client is a common early mistake.

---

## Try it in five minutes

The following creates a minimal end-to-end flow: a user provides a topic, a prompt node generates a short summary, and the output is returned.

```python
import boto3

client = boto3.client("bedrock-agent", region_name="us-east-1")
ROLE = "arn:aws:iam::123456789012:role/MyFlowsRole"  # replace

# 1. Define nodes
input_node = {
    "type": "Input", "name": "FlowInput",
    "outputs": [{"name": "document", "type": "Object"}]
}

prompt_node = {
    "type": "Prompt", "name": "Summarise",
    "configuration": {"prompt": {"sourceConfiguration": {"inline": {
        "modelId": "amazon.nova-lite-v1:0",
        "templateType": "TEXT",
        "templateConfiguration": {"text": {
            "text": "Write a 3-sentence summary of: {{topic}}"
        }},
        "inferenceConfiguration": {"text": {"temperature": 0.5}}
    }}}},
    "inputs": [{"name": "topic", "type": "String", "expression": "$.data.topic"}],
    "outputs": [{"name": "modelCompletion", "type": "String"}]
}

output_node = {
    "type": "Output", "name": "FlowOutput",
    "inputs": [{"name": "document", "type": "String", "expression": "$.data"}]
}

# 2. Wire connections
connections = [
    {"name": "in_to_prompt", "source": "FlowInput", "target": "Summarise",
     "type": "Data", "configuration": {"data": {
         "sourceOutput": "document", "targetInput": "topic"}}},
    {"name": "prompt_to_out", "source": "Summarise", "target": "FlowOutput",
     "type": "Data", "configuration": {"data": {
         "sourceOutput": "modelCompletion", "targetInput": "document"}}},
]

# 3. Create
resp = client.create_flow(
    name="TopicSummariser",
    executionRoleArn=ROLE,
    definition={"nodes": [input_node, prompt_node, output_node],
                "connections": connections}
)
flow_id = resp["id"]

# 4. Prepare + version + alias
client.prepare_flow(flowIdentifier=flow_id)
v = client.create_flow_version(flowIdentifier=flow_id)["version"]
alias = client.create_flow_alias(
    flowIdentifier=flow_id, name="prod",
    routingConfiguration=[{"flowVersion": v}]
)

# 5. Invoke
rt = boto3.client("bedrock-agent-runtime", region_name="us-east-1")
response = rt.invoke_flow(
    flowIdentifier=flow_id,
    flowAliasIdentifier=alias["id"],
    inputs=[{"nodeName": "FlowInput", "nodeOutputName": "document",
             "content": {"document": {"topic": "quantum computing"}}}]
)
for event in response["responseStream"]:
    if "flowOutputEvent" in event:
        print(event["flowOutputEvent"]["content"]["document"])
```

---

**Verified against the official AWS docs on 2026-06-10.**  
Sources:
- https://docs.aws.amazon.com/bedrock/latest/userguide/flows.html — overview and use cases
- https://docs.aws.amazon.com/bedrock/latest/userguide/key-definitions-flow.html — key concepts
- https://docs.aws.amazon.com/bedrock/latest/userguide/flows-nodes.html — all node types
- https://docs.aws.amazon.com/bedrock/latest/userguide/flows-code-ex.html — code samples
- https://docs.aws.amazon.com/bedrock/latest/userguide/flows-create-async.html — async flow executions

If the docs change, this tip is a snapshot of that day — check the sources for current behaviour.

---

*Generated by Claude Cowork · A daily experiment by Monty van Emmerik · [vanemmerik.ai](https://vanemmerik.ai/)*
