Skip to main content
Flytekit provides conditional as a first-class construct for selectively executing branches in a workflow. Conditions can test static values, workflow inputs, or outputs from upstream tasks.
Conditionals are restricted to binary and logical operators on primitive values. They are type-safe and highly performant because Flyte evaluates them without spawning additional pods.

How conditionals work

The pattern is:
result = (
    conditional("branch-name")
    .if_(some_condition)
    .then(task_a(...))
    .elif_(other_condition)
    .then(task_b(...))
    .else_()
    .fail("No condition matched")
)
Every conditional must be complete — all possible branches must be accounted for. If no branch matches, the workflow fails unless you provide .else_().fail(...) or a default .else_().then(...).
Conditionals use bitwise & and | instead of Python’s and / or. Due to Python’s PEP-335, and, or, and not cannot be overloaded. Flytekit follows the same convention used by pandas, numpy, and other libraries.

Import

import typing
from flytekit import conditional, task, workflow

Simple branch

Choose between calculate_circle_circumference and calculate_circle_area based on whether the input is a fraction (0–1) or a larger value:
@task
def calculate_circle_circumference(radius: float) -> float:
    return 2 * 3.14159 * radius


@task
def calculate_circle_area(radius: float) -> float:
    return 3.14159 * radius * radius


@workflow
def shape_properties(radius: float = 0.5) -> float:
    return (
        conditional("shape-properties")
        .if_(radius < 1.0)
        .then(calculate_circle_circumference(radius=radius))
        .else_()
        .then(calculate_circle_area(radius=radius))
    )

Multiple branches

Use .elif_() to handle multiple distinct conditions. If none matches, the workflow fails:
@task
def calculate_rectangle_area(length: float, width: float) -> float:
    return length * width


@workflow
def shape_properties_with_multiple_branches(radius: float = 0.5) -> float:
    return (
        conditional("shape-properties-multiple")
        .if_(radius < 0.0)
        .fail("Radius must be non-negative")
        .elif_((radius > 0.0) & (radius < 1.0))
        .then(calculate_circle_circumference(radius=radius))
        .elif_(radius > 1.0)
        .then(calculate_circle_area(radius=radius))
        .else_()
        .fail("Exact zero radius not handled")
    )

Consuming the output of a conditional

Pass the result of a conditional to a downstream task just like any other promise:
@task
def format_result(area: float) -> str:
    return f"The computed area is {area:.4f}"


@workflow
def shape_properties_accept_conditional_output(radius: float = 0.5) -> str:
    result = (
        conditional("shape-properties")
        .if_(radius < 1.0)
        .then(calculate_circle_circumference(radius=radius))
        .else_()
        .then(calculate_circle_area(radius=radius))
    )
    return format_result(area=result)

Using a task’s boolean output in a conditional

Use .is_true(), .is_false(), and .is_none() on promise values — unary operations are not supported directly:
@task
def coin_flip(seed: int) -> bool:
    import random
    random.seed(seed)
    return random.random() > 0.5


@workflow
def boolean_wf(seed: int = 42) -> float:
    result = coin_flip(seed=seed)
    return (
        conditional("coin-flip")
        .if_(result.is_true())
        .then(calculate_circle_circumference(radius=0.5))
        .else_()
        .then(calculate_circle_area(radius=0.5))
    )
Inside a workflow, inputs and outputs are automatically wrapped in a Promise object. This is why result has the .is_true() method — it is a Flytekit Promise, not a plain Python bool.

Using boolean workflow inputs

You can pass a boolean directly to a workflow and test it with .is_true():
@workflow
def boolean_input_wf(boolean_input: bool = True) -> float:
    return (
        conditional("boolean-input")
        .if_(boolean_input.is_true())
        .then(calculate_circle_circumference(radius=1.0))
        .else_()
        .then(calculate_circle_area(radius=1.0))
    )
The boolean workflow input is also a Promise at workflow-definition time, so it carries the same .is_true() behavior.

Nested conditionals

You can nest conditional sections inside the .then() of an outer conditional:
@workflow
def nested_conditions(radius: float = 0.7) -> float:
    return (
        conditional("outer")
        .if_(radius < 0.0)
        .fail("Negative radius")
        .elif_(radius < 1.0)
        .then(
            conditional("inner")
            .if_(radius < 0.5)
            .then(calculate_circle_circumference(radius=radius))
            .else_()
            .then(calculate_circle_area(radius=radius))
        )
        .else_()
        .then(calculate_circle_area(radius=radius))
    )
Nested conditional sections can only appear inside the .then() part of an outer conditional block.

Skipping a branch with a noop

To skip execution in one branch without side effects, use the echo task plugin, which simply passes through its input:
# Enable the echo plugin in Flyte's config:
# task-plugins:
#   enabled-plugins:
#     - echo
from flytekit.extras.tasks.shell import echo_task

@workflow
def noop_in_conditional(radius: float = 0.4, seed: int = 5) -> typing.Optional[float]:
    flip = coin_flip(seed=seed)
    return (
        conditional("noop-conditional")
        .if_(flip.is_true())
        .then(calculate_circle_circumference(radius=radius))
        .else_()
        .then(echo_task(input_val=None))
    )

Run locally

if __name__ == "__main__":
    print(shape_properties(radius=0.5))
    print(shape_properties_with_multiple_branches(radius=11.0))
    print(shape_properties_accept_conditional_output(radius=0.5))
    print(boolean_input_wf(boolean_input=True))
    print(nested_conditions(radius=0.7))

Run on the Flyte cluster

pyflyte run --remote \
  https://raw.githubusercontent.com/flyteorg/flytesnacks/656e63d1c8dded3e9e7161c7af6425e9fcd43f56/examples/advanced_composition/advanced_composition/conditional.py \
  shape_properties --radius 3.0

Build docs developers (and LLMs) love