Skip to main content
This quickstart guide will walk you through creating and running your first Metaflow flow. In just a few minutes, you’ll understand the basics of how Metaflow works.

Your First Flow

Let’s start with the classic “Hello World” example. Create a new file called helloworld.py:
helloworld.py
from metaflow import FlowSpec, step

class HelloFlow(FlowSpec):
    """
    A flow where Metaflow prints 'Hi'.

    Run this flow to validate that Metaflow is installed correctly.
    """

    @step
    def start(self):
        """
        This is the 'start' step. All flows must have a step named 'start' that
        is the first step in the flow.
        """
        print("HelloFlow is starting.")
        self.next(self.hello)

    @step
    def hello(self):
        """
        A step for metaflow to introduce itself.
        """
        print("Metaflow says: Hi!")
        self.next(self.end)

    @step
    def end(self):
        """
        This is the 'end' step. All flows must have an 'end' step, which is the
        last step in the flow.
        """
        print("HelloFlow is all done.")

if __name__ == "__main__":
    HelloFlow()

Understanding the Flow

Let’s break down the key components:
1

FlowSpec Class

Every Metaflow flow is a Python class that inherits from FlowSpec. This class defines your workflow.
class HelloFlow(FlowSpec):
2

Steps

Steps are methods decorated with @step. Each step represents a unit of work in your flow.
@step
def start(self):
    print("HelloFlow is starting.")
    self.next(self.hello)
3

Flow Navigation

Use self.next() to specify which step executes next. This creates the flow graph.
self.next(self.hello)  # Move to the hello step
4

Required Steps

Every flow must have:
  • A start step (entry point)
  • An end step (exit point)

Running Your Flow

1

View the Flow Structure

First, visualize your flow’s structure:
python helloworld.py show
This displays the flow graph, showing how steps connect to each other.
2

Run the Flow

Execute your flow:
python helloworld.py run
You’ll see output like:
Metaflow 2.19.20 executing HelloFlow for user:yourname
Validating your flow...
    The graph looks good!
Running pylint...
    Pylint is happy!
2026-03-09 10:30:15.123 [1/start/1 (pid 12345)] Task is starting.
2026-03-09 10:30:15.456 [1/start/1 (pid 12345)] HelloFlow is starting.
2026-03-09 10:30:15.789 [1/start/1 (pid 12345)] Task finished successfully.
2026-03-09 10:30:16.123 [2/hello/2 (pid 12346)] Task is starting.
2026-03-09 10:30:16.456 [2/hello/2 (pid 12346)] Metaflow says: Hi!
2026-03-09 10:30:16.789 [2/hello/2 (pid 12346)] Task finished successfully.
2026-03-09 10:30:17.123 [3/end/3 (pid 12347)] Task is starting.
2026-03-09 10:30:17.456 [3/end/3 (pid 12347)] HelloFlow is all done.
2026-03-09 10:30:17.789 [3/end/3 (pid 12347)] Task finished successfully.
Done!

Working with Data

Flows become interesting when they process data. Let’s create a flow that stores and accesses data:
data_flow.py
from metaflow import FlowSpec, step

class DataFlow(FlowSpec):
    """
    A flow that demonstrates data artifacts.
    """

    @step
    def start(self):
        """
        Create some data.
        """
        self.my_data = {"message": "Hello", "count": 42}
        print(f"Created data: {self.my_data}")
        self.next(self.process)

    @step
    def process(self):
        """
        Access and transform the data.
        """
        print(f"Received data: {self.my_data}")
        self.result = self.my_data["count"] * 2
        self.next(self.end)

    @step
    def end(self):
        """
        Display the results.
        """
        print(f"Final result: {self.result}")

if __name__ == "__main__":
    DataFlow()
Key Concept: Any instance variable you set in a step (like self.my_data) is automatically persisted and available in subsequent steps. Metaflow handles all the versioning and storage behind the scenes.
Run this flow:
python data_flow.py run

Adding Parameters

Make your flows configurable with parameters:
parameterized_flow.py
from metaflow import FlowSpec, step, Parameter

class GreetingFlow(FlowSpec):
    """
    A flow with configurable parameters.
    """

    name = Parameter('name',
                     help='Your name',
                     default='World')
    
    count = Parameter('count',
                      help='Number of greetings',
                      default=3)

    @step
    def start(self):
        """
        Generate greetings.
        """
        self.greetings = [f"Hello, {self.name}!" for _ in range(self.count)]
        self.next(self.end)

    @step
    def end(self):
        """
        Display all greetings.
        """
        for i, greeting in enumerate(self.greetings, 1):
            print(f"{i}. {greeting}")

if __name__ == "__main__":
    GreetingFlow()
Run with custom parameters:
python parameterized_flow.py run --name Alice --count 5

Command Line Interface

Metaflow provides a rich CLI for managing flows:
python myflow.py show

Next Steps

Now that you’ve created your first flows, dive deeper into Metaflow’s capabilities:

Complete Tutorial

Learn about parallel execution, data handling, and more

Core Concepts

Understand flows, steps, and artifacts in detail

Parameters & Config

Master flow configuration and parameterization

Scaling to Cloud

Run flows on cloud compute resources
Try the Metaflow Sandbox for an interactive learning experience without any setup!

Build docs developers (and LLMs) love