Core Concepts Flows
Core Concepts
Flows Copy page
Learn how to create and manage AI workflows using CrewAI Flows.
Introduction
CrewAI Flows is a powerful feature designed to streamline the creation and management
of AI workflows. Flows allow developers to combine and coordinate coding tasks and
Crews efficiently, providing a robust framework for building sophisticated AI automations.
Flows allow you to create structured, event-driven workflows. They provide a seamless
way to connect multiple tasks, manage state, and control the flow of execution in your AI
applications. With Flows, you can easily design and implement multi-step processes that
leverage the full potential of CrewAI’s capabilities.
1. Simplified Workflow Creation: Easily chain together multiple Crews and tasks to
create complex AI workflows.
2. State Management: Flows make it super easy to manage and share state between
different tasks in your workflow.
3. Event-Driven Architecture: Built on an event-driven model, allowing for dynamic and
responsive workflows.
4. Flexible Control Flow: Implement conditional logic, loops, and branching within your
workflows.
Getting Started
Let’s create a simple Flow where you will use OpenAI to generate a random city in one
task and then use that city to generate a fun fact in another task.
Code
[Link]
from Concepts Flows import Flow, listen, start
from dotenv import load_dotenv
from litellm import completion
class ExampleFlow(Flow):
model = "gpt-4o-mini"
@start()
def generate_city(self):
print("Starting flow")
# Each flow state automatically gets a unique ID
print(f"Flow State ID: {[Link]['id']}")
response = completion(
model=[Link],
messages=[
{
"role": "user",
"content": "Return the name of a random city in the world."
},
],
)
random_city = response["choices"][0]["message"]["content"]
# Store the city in our state
[Link]["city"] = random_city
print(f"Random City: {random_city}")
return random_city
@listen(generate_city)
def generate_fun_fact(self, random_city):
response = completion(
model=[Link],
messages=[
{
"role": "user",
"content": f"Tell me a fun fact about {random_city}",
},
],
)
fun_fact Flows
Core Concepts = response["choices"][0]["message"]["content"]
# Store the fun fact in our state
[Link]["fun_fact"] = fun_fact
return fun_fact
flow = ExampleFlow()
result = [Link]()
print(f"Generated fun fact: {result}")
In the above example, we have created a simple Flow that generates a random city using
OpenAI and then generates a fun fact about that city. The Flow consists of two tasks:
generate_city and generate_fun_fact . The generate_city task is the starting point
of the Flow, and the generate_fun_fact task listens for the output of the
generate_city task.
Each Flow instance automatically receives a unique identifier (UUID) in its state, which
helps track and manage flow executions. The state can also store additional data (like the
generated city and fun fact) that persists throughout the flow’s execution.
When you run the Flow, it will:
1. Generate a unique ID for the flow state
2. Generate a random city and store it in the state
3. Generate a fun fact about that city and store it in the state
4. Print the results to the console
The state’s unique ID and stored data can be useful for tracking flow executions and
maintaining context between tasks.
Note: Ensure you have set up your .env file to store your OPENAI_API_KEY . This key is
necessary for authenticating requests to the OpenAI API.
@start()
The @start() decorator is used to mark a method as the starting point of a Flow. When
a Flow
CoreisConcepts
started, all the methods decorated with @start() are executed in parallel. You
Flows
can have multiple start methods in a Flow, and they will all be executed when the Flow is
started.
@listen()
The @listen() decorator is used to mark a method as a listener for the output of
another task in the Flow. The method decorated with @listen() will be executed when
the specified task emits an output. The method can access the output of the task it is
listening to as an argument.
Usage
The @listen() decorator can be used in several ways:
1. Listening to a Method by Name: You can pass the name of the method you want to
listen to as a string. When that method completes, the listener method will be
triggered.
Code
@listen("generate_city")
def generate_fun_fact(self, random_city):
# Implementation
2. Listening to a Method Directly: You can pass the method itself. When that method
completes, the listener method will be triggered.
Code
@listen(generate_city)
def generate_fun_fact(self, random_city):
# Implementation
Flow Output
Accessing and handling the output of a Flow is essential for integrating your AI workflows
into Core
larger applications
Concepts or systems. CrewAI Flows provide straightforward mechanisms to
Flows
retrieve the final output, access intermediate results, and manage the overall state of your
Flow.
Retrieving the Final Output
When you run a Flow, the final output is determined by the last method that completes.
The kickoff() method returns the output of this final method.
Here’s how you can access the final output:
Code Output
from [Link] import Flow, listen, start
class OutputExampleFlow(Flow):
@start()
def first_method(self):
return "Output from first_method"
@listen(first_method)
def second_method(self, first_output):
return f"Second method received: {first_output}"
flow = OutputExampleFlow()
final_output = [Link]()
print("---- Final Output ----")
print(final_output)
In this example, the second_method is the last method to complete, so its output will be
the final output of the Flow. The kickoff() method will return the final output, which is
then printed to the console.
Accessing and Updating State
In addition to retrieving the final output, you can also access and update the state within
your Flow. The state can be used to store and share data between different methods in
the Flow. After the Flow has run, you can access the state to retrieve any information that
wasCore
addedConcepts
or updatedFlows
during the execution.
Here’s an example of how to update and access the state:
Code Output
from [Link] import Flow, listen, start
from pydantic import BaseModel
class ExampleState(BaseModel):
counter: int = 0
message: str = ""
class StateExampleFlow(Flow[ExampleState]):
@start()
def first_method(self):
[Link] = "Hello from first_method"
[Link] += 1
@listen(first_method)
def second_method(self):
[Link] += " - updated by second_method"
[Link] += 1
return [Link]
flow = StateExampleFlow()
final_output = [Link]()
print(f"Final Output: {final_output}")
print("Final State:")
print([Link])
In this example, the state is updated by both first_method and second_method . After
the Flow has run, you can access the final state to see the updates made by these
methods.
By ensuring that the final method’s output is returned and providing access to the state,
CrewAI Flows make it easy to integrate the results of your AI workflows into larger
applications or systems, while also maintaining and accessing the state throughout the
Core
Flow’s Concepts Flows
execution.
Flow State Management
Managing state effectively is crucial for building reliable and maintainable AI workflows.
CrewAI Flows provides robust mechanisms for both unstructured and structured state
management, allowing developers to choose the approach that best fits their application’s
needs.
Unstructured State Management
In unstructured state management, all state is stored in the state attribute of the Flow
class. This approach offers flexibility, enabling developers to add or modify state
attributes on the fly without defining a strict schema. Even with unstructured states,
CrewAI Flows automatically generates and maintains a unique identifier (UUID) for each
state instance.
Code
from [Link] import Flow, listen, start
Core Concepts Flows
class UnstructuredExampleFlow(Flow):
@start()
def first_method(self):
# The state automatically includes an 'id' field
print(f"State ID: {[Link]['id']}")
[Link]['counter'] = 0
[Link]['message'] = "Hello from structured flow"
@listen(first_method)
def second_method(self):
[Link]['counter'] += 1
[Link]['message'] += " - updated"
@listen(second_method)
def third_method(self):
[Link]['counter'] += 1
[Link]['message'] += " - updated again"
print(f"State after third_method: {[Link]}")
flow = UnstructuredExampleFlow()
[Link]()
Note: The id field is automatically generated and preserved throughout the flow’s
execution. You don’t need to manage or set it manually, and it will be maintained even
when updating the state with new data.
Key Points:
Flexibility: You can dynamically add attributes to [Link] without predefined
constraints.
Simplicity: Ideal for straightforward workflows where state structure is minimal or
varies significantly.
Structured State Management
Structured state management leverages predefined schemas to ensure consistency and
typeCore
safety across the
Concepts workflow. By using models like Pydantic’s BaseModel , developers
Flows
can define the exact shape of the state, enabling better validation and auto-completion in
development environments.
Each state in CrewAI Flows automatically receives a unique identifier (UUID) to help track
and manage state instances. This ID is automatically generated and managed by the Flow
system.
Code
from [Link] import Flow, listen, start
Corepydantic
from Concepts import
FlowsBaseModel
class ExampleState(BaseModel):
# Note: 'id' field is automatically added to all states
counter: int = 0
message: str = ""
class StructuredExampleFlow(Flow[ExampleState]):
@start()
def first_method(self):
# Access the auto-generated ID if needed
print(f"State ID: {[Link]}")
[Link] = "Hello from structured flow"
@listen(first_method)
def second_method(self):
[Link] += 1
[Link] += " - updated"
@listen(second_method)
def third_method(self):
[Link] += 1
[Link] += " - updated again"
print(f"State after third_method: {[Link]}")
flow = StructuredExampleFlow()
[Link]()
Key Points:
Defined Schema: ExampleState clearly outlines the state structure, enhancing code
readability and maintainability.
Type Safety: Leveraging Pydantic ensures that state attributes adhere to the
specified types, reducing runtime errors.
Auto-Completion: IDEs can provide better auto-completion and error checking based
Core Concepts Flows
on the defined state model.
Choosing Between Unstructured and Structured State Management
Use Unstructured State Management when:
The workflow’s state is simple or highly dynamic.
Flexibility is prioritized over strict state definitions.
Rapid prototyping is required without the overhead of defining schemas.
Use Structured State Management when:
The workflow requires a well-defined and consistent state structure.
Type safety and validation are important for your application’s reliability.
You want to leverage IDE features like auto-completion and type checking for
better developer experience.
By providing both unstructured and structured state management options, CrewAI Flows
empowers developers to build AI workflows that are both flexible and robust, catering to
a wide range of application requirements.
Flow Persistence
The @persist decorator enables automatic state persistence in CrewAI Flows, allowing
you to maintain flow state across restarts or different workflow executions. This decorator
can be applied at either the class level or method level, providing flexibility in how you
manage state persistence.
Class-Level Persistence
When applied at the class level, the @persist decorator automatically persists all flow
method states:
@persist # Using SQLiteFlowPersistence by default
class MyFlow(Flow[MyState]):
@start()
Core Concepts Flows
def initialize_flow(self):
# This method will automatically have its state persisted
[Link] = 1
print("Initialized flow. State ID:", [Link])
@listen(initialize_flow)
def next_step(self):
# The state (including [Link]) is automatically reloaded
[Link] += 1
print("Flow state is persisted. Counter:", [Link])
Method-Level Persistence
For more granular control, you can apply @persist to specific methods:
class AnotherFlow(Flow[dict]):
@persist # Persists only this method's state
@start()
def begin(self):
if "runs" not in [Link]:
[Link]["runs"] = 0
[Link]["runs"] += 1
print("Method-level persisted runs:", [Link]["runs"])
How It Works
1. Unique State Identification
Each flow state automatically receives a unique UUID
The ID is preserved across state updates and method calls
Supports both structured (Pydantic BaseModel) and unstructured (dictionary)
states
2. Default SQLite Backend
SQLiteFlowPersistence is the default storage backend
States are automatically saved to a local SQLite database
Core Robust
ConceptserrorFlows
handling ensures clear messages if database operations fail
3. Error Handling
Comprehensive error messages for database operations
Automatic state validation during save and load
Clear feedback when persistence operations encounter issues
Important Considerations
State Types: Both structured (Pydantic BaseModel) and unstructured (dictionary)
states are supported
Automatic ID: The id field is automatically added if not present
State Recovery: Failed or restarted flows can automatically reload their previous
state
Custom Implementation: You can provide your own FlowPersistence implementation
for specialized storage needs
Technical Advantages
1. Precise Control Through Low-Level Access
Direct access to persistence operations for advanced use cases
Fine-grained control via method-level persistence decorators
Built-in state inspection and debugging capabilities
Full visibility into state changes and persistence operations
2. Enhanced Reliability
Automatic state recovery after system failures or restarts
Transaction-based state updates for data integrity
Comprehensive error handling with clear error messages
Robust validation during state save and load operations
3. Extensible Architecture
Core Concepts Flows
Customizable persistence backend through FlowPersistence interface
Support for specialized storage solutions beyond SQLite
Compatible with both structured (Pydantic) and unstructured (dict) states
Seamless integration with existing CrewAI flow patterns
The persistence system’s architecture emphasizes technical precision and customization
options, allowing developers to maintain full control over state management while
benefiting from built-in reliability features.
Flow Control
Conditional Logic: or
The or_ function in Flows allows you to listen to multiple methods and trigger the
listener method when any of the specified methods emit an output.
Code Output
from [Link] import Flow, listen, or_, start
Core Concepts Flows
class OrExampleFlow(Flow):
@start()
def start_method(self):
return "Hello from the start method"
@listen(start_method)
def second_method(self):
return "Hello from the second method"
@listen(or_(start_method, second_method))
def logger(self, result):
print(f"Logger: {result}")
flow = OrExampleFlow()
[Link]()
When you run this Flow, the logger method will be triggered by the output of either the
start_method or the second_method . The or_ function is used to listen to multiple
methods and trigger the listener method when any of the specified methods emit an
output.
Conditional Logic: and
The and_ function in Flows allows you to listen to multiple methods and trigger the
listener method only when all the specified methods emit an output.
Code Output
from [Link] import Flow, and_, listen, start
Core Concepts Flows
class AndExampleFlow(Flow):
@start()
def start_method(self):
[Link]["greeting"] = "Hello from the start method"
@listen(start_method)
def second_method(self):
[Link]["joke"] = "What do computers eat? Microchips."
@listen(and_(start_method, second_method))
def logger(self):
print("---- Logger ----")
print([Link])
flow = AndExampleFlow()
[Link]()
When you run this Flow, the logger method will be triggered only when both the
start_method and the second_method emit an output. The and_ function is used to
listen to multiple methods and trigger the listener method only when all the specified
methods emit an output.
Router
The @router() decorator in Flows allows you to define conditional routing logic based
on the output of a method. You can specify different routes based on the output of the
method, allowing you to control the flow of execution dynamically.
Code Output
import random
Core [Link]
from Concepts Flows import Flow, listen, router, start
from pydantic import BaseModel
class ExampleState(BaseModel):
success_flag: bool = False
class RouterFlow(Flow[ExampleState]):
@start()
def start_method(self):
print("Starting the structured flow")
random_boolean = [Link]([True, False])
[Link].success_flag = random_boolean
@router(start_method)
def second_method(self):
if [Link].success_flag:
return "success"
else:
return "failed"
@listen("success")
def third_method(self):
print("Third method running")
@listen("failed")
def fourth_method(self):
print("Fourth method running")
flow = RouterFlow()
[Link]()
In the above example, the start_method generates a random boolean value and sets it
in the state. The second_method uses the @router() decorator to define conditional
routing logic based on the value of the boolean. If the boolean is True , the method
returns "success" , and if it is False , the method returns "failed" . The
third_method and fourth_method listen to the output of the second_method and
execute based on the returned value.
When youConcepts
Core run this Flow, the output will change based on the random boolean value
Flows
generated by the start_method .
Adding Agents to Flows
Agents can be seamlessly integrated into your flows, providing a lightweight alternative to
full Crews when you need simpler, focused task execution. Here’s an example of how to
use an Agent within a flow to perform market research:
import asyncio
from typing import Any, Dict, List
Core Concepts Flows
from crewai_tools import SerperDevTool
from pydantic import BaseModel, Field
from [Link] import Agent
from [Link] import Flow, listen, start
# Define a structured output format
class MarketAnalysis(BaseModel):
key_trends: List[str] = Field(description="List of identified market trends
market_size: str = Field(description="Estimated market size")
competitors: List[str] = Field(description="Major competitors in the space"
# Define flow state
class MarketResearchState(BaseModel):
product: str = ""
analysis: MarketAnalysis | None = None
# Create a flow class
class MarketResearchFlow(Flow[MarketResearchState]):
@start()
def initialize_research(self) -> Dict[str, Any]:
print(f"Starting market research for {[Link]}")
return {"product": [Link]}
@listen(initialize_research)
async def analyze_market(self) -> Dict[str, Any]:
# Create an Agent for market research
analyst = Agent(
role="Market Research Analyst",
goal=f"Analyze the market for {[Link]}",
backstory="You are an experienced market analyst with expertise in
"identifying market trends and opportunities.",
tools=[SerperDevTool()],
verbose=True,
)
# Define the research query
query = f"""
Research the market for {[Link]}. Include:
1. Key market
Core Concepts Flows trends
2. Market size
3. Major competitors
Format your response according to the specified structure.
"""
# Execute the analysis with structured output format
result = await analyst.kickoff_async(query, response_format=MarketAnaly
if [Link]:
print("result", [Link])
else:
print("result", result)
# Return the analysis to update the state
return {"analysis": [Link]}
@listen(analyze_market)
def present_results(self, analysis) -> None:
print("\nMarket Analysis Results")
print("=====================")
if isinstance(analysis, dict):
# If we got a dict with 'analysis' key, extract the actual analysis
market_analysis = [Link]("analysis")
else:
market_analysis = analysis
if market_analysis and isinstance(market_analysis, MarketAnalysis):
print("\nKey Market Trends:")
for trend in market_analysis.key_trends:
print(f"- {trend}")
print(f"\nMarket Size: {market_analysis.market_size}")
print("\nMajor Competitors:")
for competitor in market_analysis.competitors:
print(f"- {competitor}")
else:
print("No structured analysis data available.")
print("Raw analysis:", analysis)
# Core
Usage example Flows
Concepts
async def run_flow():
flow = MarketResearchFlow()
result = await flow.kickoff_async(inputs={"product": "AI-powered chatbots"}
return result
# Run the flow
if __name__ == "__main__":
[Link](run_flow())
This example demonstrates several key features of using Agents in flows:
1. Structured Output: Using Pydantic models to define the expected output format
( MarketAnalysis ) ensures type safety and structured data throughout the flow.
2. State Management: The flow state ( MarketResearchState ) maintains context
between steps and stores both inputs and outputs.
3. Tool Integration: Agents can use tools (like WebsiteSearchTool ) to enhance their
capabilities.
Adding Crews to Flows
Creating a flow with multiple crews in CrewAI is straightforward.
You can generate a new CrewAI project that includes all the scaffolding needed to create
a flow with multiple crews by running the following command:
crewai create flow name_of_flow
This command will generate a new CrewAI project with the necessary folder structure.
The generated project includes a prebuilt crew called poem_crew that is already working.
You can use this crew as a template by copying, pasting, and editing it to create other
crews.
Core Concepts Flows
Folder Structure
After running the crewai create flow name_of_flow command, you will see a folder
structure similar to the following:
Directory/File Description
name_of_flow/ Root directory for the flow.
├── crews/ Contains directories for specific crews.
│ └── poem_crew/ Directory for the “poem_crew” with its configurations and scripts.
│ ├── config/ Configuration files directory for the “poem_crew”.
│ │ ├── [Link] YAML file defining the agents for “poem_crew”.
│ │ └── [Link] YAML file defining the tasks for “poem_crew”.
│ ├── poem_crew.py Script for “poem_crew” functionality.
├── tools/ Directory for additional tools used in the flow.
│ └── custom_tool.py Custom tool implementation.
├── [Link] Main script for running the flow.
├── [Link] Project description and instructions.
├── [Link] Configuration file for project dependencies and settings.
└── .gitignore Specifies files and directories to ignore in version control.
Building Your Crews
In the crews folder, you can define multiple crews. Each crew will have its own folder
containing configuration files and the crew definition file. For example, the poem_crew
folder contains:
config/[Link] : Defines the agents for the crew.
config/[Link] : Defines the tasks for the crew.
poem_crew.py : Contains the crew definition, including agents, tasks, and the crew
itself.
You Core
can copy, paste,Flows
Concepts and edit the poem_crew to create other crews.
Connecting Crews in [Link]
The [Link] file is where you create your flow and connect the crews together. You can
define your flow by using the Flow class and the decorators @start and @listen to
specify the flow of execution.
Here’s an example of how you can connect the poem_crew in the [Link] file:
Code
#!/usr/bin/env python
Corerandom
from Conceptsimport
Flows
randint
from pydantic import BaseModel
from [Link] import Flow, listen, start
from .crews.poem_crew.poem_crew import PoemCrew
class PoemState(BaseModel):
sentence_count: int = 1
poem: str = ""
class PoemFlow(Flow[PoemState]):
@start()
def generate_sentence_count(self):
print("Generating sentence count")
[Link].sentence_count = randint(1, 5)
@listen(generate_sentence_count)
def generate_poem(self):
print("Generating poem")
result = PoemCrew().crew().kickoff(inputs={"sentence_count": [Link]
print("Poem generated", [Link])
[Link] = [Link]
@listen(generate_poem)
def save_poem(self):
print("Saving poem")
with open("[Link]", "w") as f:
[Link]([Link])
def kickoff():
poem_flow = PoemFlow()
poem_flow.kickoff()
def plot():
poem_flow = PoemFlow()
poem_flow.plot()
if __name__ == "__main__":
kickoff()
Core Concepts Flows
In this example, the PoemFlow class defines a flow that generates a sentence count,
uses the PoemCrew to generate a poem, and then saves the poem to a file. The flow is
kicked off by calling the kickoff() method.
Running the Flow
(Optional) Before running the flow, you can install the dependencies by running:
crewai install
Once all of the dependencies are installed, you need to activate the virtual environment
by running:
source .venv/bin/activate
After activating the virtual environment, you can run the flow by executing one of the
following commands:
crewai flow kickoff
or
uv run kickoff
The flow will execute, and you should see the output in the console.
Plot Flows
Visualizing your AI workflows can provide valuable insights into the structure and
execution paths of your flows. CrewAI offers a powerful visualization tool that allows you
to generate interactive plots of your flows, making it easier to understand and optimize
yourCore Concepts Flows
AI workflows.
What are Plots?
Plots in CrewAI are graphical representations of your AI workflows. They display the
various tasks, their connections, and the flow of data between them. This visualization
helps in understanding the sequence of operations, identifying bottlenecks, and ensuring
that the workflow logic aligns with your expectations.
How to Generate a Plot
CrewAI provides two convenient methods to generate plots of your flows:
Option 1: Using the plot() Method
If you are working directly with a flow instance, you can generate a plot by calling the
plot() method on your flow object. This method will create an HTML file containing the
interactive plot of your flow.
Code
# Assuming you have a flow instance
[Link]("my_flow_plot")
This will generate a file named my_flow_plot.html in your current directory. You can
open this file in a web browser to view the interactive plot.
Option 2: Using the Command Line
If you are working within a structured CrewAI project, you can generate a plot using the
command line. This is particularly useful for larger projects where you want to visualize
the entire flow setup.
crewai flow plot
Core Concepts Flows
This command will generate an HTML file with the plot of your flow, similar to the
plot() method. The file will be saved in your project directory, and you can open it in a
web browser to explore the flow.
Understanding the Plot
The generated plot will display nodes representing the tasks in your flow, with directed
edges indicating the flow of execution. The plot is interactive, allowing you to zoom in
and out, and hover over nodes to see additional details.
By visualizing your flows, you can gain a clearer understanding of the workflow’s
structure, making it easier to debug, optimize, and communicate your AI processes to
others.
Conclusion
Plotting your flows is a powerful feature of CrewAI that enhances your ability to design
and manage complex AI workflows. Whether you choose to use the plot() method or
the command line, generating plots will provide you with a visual representation of your
workflows, aiding in both development and presentation.
Next Steps
If you’re interested in exploring additional examples of flows, we have a variety of
recommendations in our examples repository. Here are four specific flow examples, each
showcasing unique use cases to help you match your current problem type to a specific
example:
1. Email Auto Responder Flow: This example demonstrates an infinite loop where a
background job continually runs to automate email responses. It’s a great use case
for tasks that need to be performed repeatedly without manual intervention. View
Example
2. Lead Score Flow: This flow showcases adding human-in-the-loop feedback and
handling different conditional branches using the router. It’s an excellent example of
how to incorporate dynamic decision-making and human oversight into your
Core Concepts
workflows. ViewFlows
Example
3. Write a Book Flow: This example excels at chaining multiple crews together, where
the output of one crew is used by another. Specifically, one crew outlines an entire
book, and another crew generates chapters based on the outline. Eventually,
everything is connected to produce a complete book. This flow is perfect for
complex, multi-step processes that require coordination between different tasks.
View Example
4. Meeting Assistant Flow: This flow demonstrates how to broadcast one event to
trigger multiple follow-up actions. For instance, after a meeting is completed, the flow
can update a Trello board, send a Slack message, and save the results. It’s a great
example of handling multiple outcomes from a single event, making it ideal for
comprehensive task management and notification systems. View Example
By exploring these examples, you can gain insights into how to leverage CrewAI Flows for
various use cases, from automating repetitive tasks to managing complex, multi-step
processes with dynamic decision-making and human feedback.
Also, check out our YouTube video on how to use flows in CrewAI below!
CrewAI Flows | Sales Pipeline Flow Demo
Running Flows
There are two ways to run a flow:
Using
Corethe Flow API
Concepts Flows
You can run a flow programmatically by creating an instance of your flow class and
calling the kickoff() method:
flow = ExampleFlow()
result = [Link]()
Using the CLI
Starting from version 0.103.0, you can run flows using the crewai run command:
crewai run
This command automatically detects if your project is a flow (based on the type =
"flow" setting in your [Link]) and runs it accordingly. This is the recommended
way to run flows from the command line.
For backward compatibility, you can also use:
crewai flow kickoff
However, the crewai run command is now the preferred method as it works for both
crews and flows.
Was this page helpful? Yes No
Crews Knowledge
Powered by Mintlify
Core Concepts Flows