# CrewAI Flows: When to Use Them and How to Build One

> CrewAI Flows explained: the @start, @listen and @router decorators, state and @persist, human feedback, chat flows, and when a Flow beats a lone crew.

_Source: https://professionalstoolkit.com/articles/crewai-flows — The Professional's Toolkit · updated November 2026_

---

A CrewAI Flow is an event-driven workflow in the open-source CrewAI framework that chains crews, single agents and plain Python code, carries shared state from step to step, and can branch, loop and wait on conditions [1]. Use one when you, not the agents, should decide which steps run, in what order and under what conditions; keep a lone crew when the path to the answer is open-ended. Building one takes three commands: `crewai create flow`, `crewai install` and `crewai run`. Three decorators carry the logic. CrewAI's docs go further and recommend starting any production application with a Flow. Running one locally costs nothing from CrewAI, though model calls bill to your LLM provider.


**3** — Core decorators carry a Flow's logic: @start, @listen and @router.



- **MIT** — Flows ship in the open-source framework
- **1.8.0+** — CrewAI version needed for @human_feedback
- **7 days** — Life of an AMP HITL email reply token


## Crew or Flow: who picks the next step

The split is about control. A crew hands a goal to role-based agents, which work through tasks in sequence or under a manager agent, and the route they take is theirs to choose. A Flow fixes the route in code: one step feeds the next, a router picks a branch, and a person can approve before anything leaves the building. CrewAI's guide on evaluating use cases frames it as a grid: crews for creative or analytical work, Flows for precise structured output, and Flows orchestrating several crews when a job needs both.

Most real jobs land in that third box. A follow-up process needs a fixed order (pull the record, score it, draft, approve, send), yet the drafting step gains from a writer and a reviewer agent working it over. That is a Flow with a crew inside one step. The reverse case is narrower than people expect. When a step only needs one structured answer, CrewAI's first-flow guide says a direct LLM call is more efficient than spinning up a crew, so not every step deserves agents.


> 💡 **Count tokens across the whole flow:** After a run, flow.usage_metrics totals token usage across every crew and bare LLM call in the flow, while the token_usage returned by the flow's kickoff reflects only the last crew that ran.


## Three decorators and the state they share

Every Flow is a Python class whose methods are wired together by decorators. `@start` marks an entry point; a flow can have several, they can run in parallel, and each runs once rather than looping on itself. `@listen` makes a method run when another method emits output. `@router` returns a label, and the listeners waiting on that label run next, which is how branches and loops are written. Two combinators widen a trigger: `or_` fires when any listed method finishes, and `and_` waits until all of them have.

State is the other half. It can be unstructured, a dictionary you write keys into, which the docs suggest for quick prototypes, or structured, a Pydantic BaseModel with type checks and validation for anything larger. **Every state gets a UUID `id`** that stays fixed for the life of the run and is the handle for saving and restoring it. State is also how steps talk to crews: a flow passes state values in as a crew's inputs and writes the crew's `result.raw` back for the next step.

Steps do not have to be crews. A single Agent can run inside a flow as a lighter step, returning structured Pydantic output through `response_format`, while plain Python methods call APIs or reshape data between agent steps. Every Flow also has built-in memory methods, `remember`, `recall` and `extract_memories`, backed by LanceDB on disk, so what one run stores can inform the next. That mix of code, agents and memory under one state object is what a crew alone does not give you.

## From scaffold to a first run

1. `crewai create flow <name>` asks for a provider, a model and an API key, saves them to `.env`, and scaffolds a project marked `type = flow` in `pyproject.toml`, with the logic in `src/<project>/main.py`, a `crews` folder and a working `poem_crew`.
2. `crewai install` installs and locks the dependencies with uv.
3. `crewai run` detects the flow and runs it; `--inputs` passes inputs as JSON.
4. `crewai flow plot` draws the flow's structure as an HTML diagram.

CrewAI's first-flow guide builds something more useful than the poem. It takes user input, makes a direct LLM call that returns a Pydantic-structured outline, then hands that outline to a writer agent and a reviewer agent running in sequence, all over typed state joined by `@start` and `@listen` [2]. One catch: its outline call uses an OpenAI model, so it needs an OpenAI key even if your agents run on Gemini or Anthropic. New crews are JSON-first (`crew.jsonc`, `agents/*.jsonc`, loaded with `load_crew`); our [CrewAI tutorial](/articles/crewai-tutorial) covers installing the CLI step by step.

## Saving progress and pausing for a person

`@persist` saves flow state to a local SQLite database by default. Put it on the class and state is saved after every method; put it on one method and only that step saves. A custom `FlowPersistence` backend can replace SQLite. Persisted state is what lets a flow come back after a crash or sit waiting for a reviewer. It also changes how you restart work, and that part changed in CrewAI v1.14.5.

Passing an earlier state id inside the kickoff inputs still resumes a run under the same id, but the docs mark that path deprecated, with no removal date yet [3]. The replacement since v1.14.5, `restore_from_state_id`, forks instead: it loads the saved snapshot into a new run with a fresh id and leaves the source history untouched. That suits *what-if* reruns and audits alike. Combining it with a checkpoint restore raises an error, so pick one recovery path per run.


> ⚠ **Unknown state ids fail silently:** If restore_from_state_id gets an id that is not found, kickoff falls back to default behavior with no exception, so check the id before trusting a restored run.


`@human_feedback`, added in January 2026 and requiring CrewAI 1.8.0 or newer, pauses a flow for review. By default it collects feedback in the console and blocks. A custom provider can instead pause the flow for Slack, email or webhook feedback; paused flows are persisted automatically and resumed with `resume` or `resume_async`. With `emit` outcomes, an LLM maps free-form comments onto one listed outcome, so approve, reject and revise become routes. With `learn=True` and flow memory enabled, lessons go into flow memory and pre-review later outputs.

## Chat, JSON definitions and live streaming

Conversational flows became stable in August 2026. Each user message is a new run under the same session id, and CrewAI supplies message history, a built-in router with converse and end listeners, per-turn tracing and a local chat terminal. You write only your custom routes, as `@listen` handlers with a one-line docstring the router reads. Apps send every message through `handle_turn()`; `flow.chat()` and `crewai run` open the terminal loop locally. Name a handler after its own route label and the flow is rejected at creation.

Declarative flows arrived in June 2026. A flow can be defined in JSON, with crew actions, single-agent actions and loops over items, and run with `crewai run --definition` without writing Python. For live interfaces, setting `stream=True` turns kickoff into a stream session of ordered frames on the llm, flow, tools, messages, lifecycle and custom channels, so a UI can render tokens and tool activity as they happen. Consume the stream fully before reading its result. Otherwise the call raises an error.


> 💡 **Persist one terminal step in chat:** For conversational flows the docs advise @persist on a single terminal step, because class-level persistence saves after every method and the latest row may be a mid-run snapshot.


## Running flows on AMP and building them in Studio

Flows run anywhere Python runs. Deploying one to CrewAI AMP (Agent Management Platform), the paid platform around the framework, turns it into an automation with its own API, triggers and traces. Two details are specific to Flows there. Status progress counts steps with a total of null, because a flow chooses its next step while running. And reusing an old id in the inputs collapses separate runs into one execution record, so the AMP kickoff takes a top-level `restoreFromStateId` field instead.

AMP's Flow HITL management turns `@human_feedback` into a review queue, and it applies to Flows, not crews. Reviewers answer by replying to the notification email without a platform account, from the dashboard, or through an API or webhook. Email reply tokens expire after 7 days, and an optional timeout can answer with a default outcome when nobody responds. Every decision is logged. Failed webhook deliveries are not retried, so an endpoint that is down misses that request.

No-code builders get Studio Flows, rolling out gradually since July 2026, so some organizations may not see the option yet [4]. A Studio Flow mixes three node types: Single Agent, Crew and Router. You can run it, inspect the Output and Traces tabs, deploy, share or download it as source code. **The download is one-way**: edited code cannot return to the visual editor. Our [CrewAI Studio guide](/articles/crewai-studio) covers the builder, and the four official example flows (Email Auto Responder, Lead Score, Write a Book, Meeting Assistant) are walked through in [CrewAI examples](/articles/crewai-examples).


## FAQ

**Do I need CrewAI AMP to run a Flow?**

No. Flows are part of the MIT-licensed open-source framework and run locally with crewai run. You need a CrewAI AMP account to deploy them as hosted automations and for AMP features such as built-in tracing, Studio Flows and email review queues; its free Basic plan includes 2 automations and 50 workflow executions a month.

**Which Python versions do CrewAI Flows support?**

The CrewAI framework needs Python 3.10 or newer and below 3.14. The @human_feedback decorator additionally needs CrewAI 1.8.0 or newer.

**Can a Flow power a web frontend?**

Yes. The ag-ui-crewai package exposes any Crew or Flow as an AG-UI endpoint served by FastAPI for CopilotKit frontends, and shared live UI state works only with a Flow that has custom state.

**Is crewai flow kickoff still the command to run a flow?**

No. That legacy command is deprecated; crewai run detects a flow through type = flow in pyproject.toml and is the recommended way to run it.


## When the extra wiring of a Flow pays off

A Flow asks for some upfront work: a state model, decorators, a decision about where to persist. It repays that once a job has a fixed order, a branch, a human approval or a frontend that must show progress, because those are exactly the parts a crew leaves to its agents. For one open-ended research or writing task, a crew on its own is less code. For a process people will lean on every week, start with the Flow and drop a crew into the step that needs judgment.



## Sources

[1] CrewAI documentation: Flows — https://docs.crewai.com/en/concepts/flows (2026-11)
[2] CrewAI documentation: Build Your First Flow — https://docs.crewai.com/en/guides/flows/first-flow (2026-11)
[3] CrewAI documentation: Migrating from inputs.id to restore_from_state_id — https://docs.crewai.com/en/guides/flows/inputs-id-deprecation (2026-11)
[4] CrewAI AMP documentation: Flows in Studio — https://docs-platform.crewai.com/platform/en/features/studio-flows (2026-11)
[5] CrewAI pricing — https://crewai.com/pricing
[6] CrewAI documentation: Installation — https://docs.crewai.com/en/installation
[7] CrewAI Terms of Use — https://crewai.com/terms-of-use
[8] AWS Marketplace: CrewAI Enterprise Platform reviews (from G2) — https://aws.amazon.com/marketplace/reviews/reviews-list/prodview-2lisdk6meykru

