Crews vs Flows
A Crew is a frozen plan: list of agents, list of tasks, one process. A Flow is a graph of methods that decides at runtime what comes next. Use Crews for "research → write" pipelines; reach for Flows when you have branching, retries, human pauses, or several crews chained together.
The Flow Class
Subclass Flow[StateType] to get typed Pydantic state. kickoff() runs synchronously on the flow; kickoff_async() returns a coroutine for async hosts.
from crewai.flow.flow import Flow, start, listen
from pydantic import BaseModel
class State(BaseModel):
topic: str = ""
draft: str = ""
class WriteFlow(Flow[State]):
@start()
def begin(self):
self.state.topic = "AI agents"
return self.state.topic
@listen(begin)
def draft(self, topic):
self.state.draft = f"Article on {topic}"
return self.state.draft
flow = WriteFlow()
print(flow.kickoff().raw)
Control Primitives
- ▸@start() — entry point. Multiple starts allowed; conditional via a state key argument.
- ▸@listen(method) — fires after the upstream completes. Combine
and_()for fan-in joins oror_()when the first branch to finish should trigger downstream work. - ▸@router(method) — return a string tag; downstream listeners listen on the tag value.
- ▸@persist() — save state to SqliteProvider (default) or JsonProvider. Pair with
CheckpointConfig.
State Management
Two flavors:
- •Structured —
Flow[MyPydanticModel]. Recommended for production: typed, validated, serializable. - •Unstructured — dict-like
self.state["key"]. Quick, fragile.
⚠️ Mutate state in place. self.state = new_obj replaces the reference and breaks references in downstream methods.
Persistence & Resumability
Apply @persist() to the class. State is keyed by an automatic state ID; pass it back into flow.kickoff() to resume. Override the backend via CheckpointConfig(storage=JsonProvider()).
Streaming
Pass stream=True to Flow constructor. Listen to LLMStreamChunkEvent and LLMThinkingChunkEvent via a BaseEventListener to forward chunks to your UI.
Adding Crews to Flows
Flows can call Crews as just another step:
@listen(begin)
def research(self, topic):
crew = ResearchCrew().crew()
result = crew.kickoff(inputs={"topic": topic})
self.state.draft = result.raw
return result.raw
Plotting
Call flow.plot("my_flow") to render an HTML diagram of starts/listeners/routers. Great for documentation and reviews.
Reference
For cross-run facts outside typed Flow state, use the unified memory APIs self.remember() and self.recall() so agents retrieve semantically instead of stuffing large blobs into state.
Notes
Flow state should stay JSON-serializable when possible
Rich Python objects complicate persistence, retries, and distributed workers. Prefer plain dicts for anything you might checkpoint or replay.
Routers need explicit fallbacks
LLM-chosen branches can oscillate under tiny prompt changes. Define a default path when confidence is low and log branch decisions for later review.
Streaming plus side effects is risky
If users read partial tokens while tools fire in the background, you can create inconsistent UX. Gate tool execution until the user confirms or the stream finalizes when actions are irreversible.
Plot helpers belong out of hot paths
Visualization is great for notebooks but expensive in tight loops. Generate charts on demand or in admin-only routes.
CrewAI Flows FAQ
What problem do CrewAI Flows solve?
Flows add event-driven orchestration with branching, fan-in, persistence, and streaming while still letting you embed crews where agent-heavy work belongs.
What is a Flow listener in CrewAI?
Listeners connect methods so that when an upstream step finishes, downstream methods run with its outputs, optionally combined with router tags for conditional paths.
How does Flow state differ from Crew state?
Flow state is typed Pydantic data you control across methods, while crew state is mostly task outputs and memory features. Flows are better for long-lived workflows.
Can Flows call CrewAI crews?
Yes. Common production patterns wrap a crew kickoff inside a Flow method so you get graph control around a stable multi-agent unit.
When should I avoid CrewAI Flows?
Skip Flows when a simple sequential crew already fits. Extra graph machinery only pays off when you need branching, human pauses, retries, or external event integration.
See also: DevShelfHub's CrewAI tool review for a product-level comparison, pricing notes, and links back into this tutorial series.