DS DevShelfHub Projects · AI tools
Flows Production · 18 min read Page 16 of 29

CrewAI Flows: Decorator Orchestration for Production Pipelines

By DevShelfHub

Flows are CrewAI's production orchestrator. They wire methods together with @start, @listen, @router, and @persist — giving you typed state, branching, fan-in, streaming, and resumability that a plain Crew can't.

Series progress16 / 29
CrewAI flows tutorial — CrewAI Flows: Decorator Orchestration for Production Pipelines

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.

python
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 or or_() 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:

  • StructuredFlow[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:

python
@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.

API details: Flow, @start, @listen, @router, @persist.

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.

Quick jump: API Reference