Skip to main content
Flyte workflows are represented as directed acyclic graphs (DAGs) defined in Protobuf. The schema lives in flyteidl/core/workflow.proto and flyteidl/core/workflow_closure.proto.

WorkflowClosure

The top-level container when registering a workflow. It bundles the workflow template with all tasks it references.
// flyteidl/core/workflow_closure.proto
message WorkflowClosure {
  // required. The workflow template.
  WorkflowTemplate workflow = 1;

  // optional. All tasks referenced by the workflow.
  repeated TaskTemplate tasks = 2;
}
workflow
WorkflowTemplate
required
The complete workflow definition including all nodes and output bindings.
tasks
TaskTemplate[]
All tasks that this workflow’s nodes execute. Required if any TaskNode is present.

WorkflowTemplate

WorkflowTemplate is the core workflow structure — a statically-analyzable DAG.
// flyteidl/core/workflow.proto
message WorkflowTemplate {
  Identifier id = 1;              // globally unique identifier
  WorkflowMetadata metadata = 2;  // QoS, failure policy, tags
  TypedInterface interface = 3;   // input/output variable declarations
  repeated Node nodes = 4;        // graph nodes
  repeated Binding outputs = 5;   // how to construct workflow outputs
  Node failure_node = 6;          // optional catch-all failure handler
  WorkflowMetadataDefaults metadata_defaults = 7; // defaults for child nodes
}

Node

A Node is one unit of execution in the workflow graph. Every node has a unique ID within the workflow and may reference a task, sub-workflow, or branch.
message Node {
  string id = 1;                         // workflow-unique identifier
  NodeMetadata metadata = 2;             // name, timeout, retries, cache settings
  repeated Binding inputs = 3;           // input bindings
  repeated string upstream_node_ids = 4; // explicit upstream dependencies
  repeated Alias output_aliases = 5;     // output aliases for downstream nodes

  oneof target {
    TaskNode task_node = 6;        // executes a registered task
    WorkflowNode workflow_node = 7; // executes a sub-workflow or launch plan
    BranchNode branch_node = 8;    // conditional branching
    GateNode gate_node = 9;        // approval / signal / sleep gate
    ArrayNode array_node = 10;     // map over a list of inputs
  }
}

NodeMetadata

message NodeMetadata {
  string name = 1;                   // friendly display name
  google.protobuf.Duration timeout = 4;  // total node timeout
  RetryStrategy retries = 5;         // retry configuration
  bool interruptible = 6;            // allow spot/preemptible interruption
  bool cacheable = 7;                // enable output caching
  string cache_version = 8;          // cache key version string
  bool cache_serializable = 9;       // serialize cache lookups
  map<string, string> config = 10;   // propeller configuration hints
}

Node target types

TaskNode

Executes a registered task.
message TaskNode {
  oneof reference {
    Identifier reference_id = 1;  // globally unique task identifier
  }
  TaskNodeOverrides overrides = 2; // optional runtime overrides
}

message TaskNodeOverrides {
  Resources resources = 1;              // CPU/memory overrides
  ExtendedResources extended_resources = 2; // GPU accelerator overrides
  string container_image = 3;           // image override
  K8sPod pod_template = 4;             // pod template override
}

WorkflowNode

Executes a sub-workflow inline or launches a separate execution via a launch plan.
message WorkflowNode {
  oneof reference {
    Identifier launchplan_ref = 1;   // launch as a separate execution
    Identifier sub_workflow_ref = 2; // execute inline as a sub-workflow
  }
}

BranchNode

Conditionally executes one of several branches based on runtime values.
message BranchNode {
  IfElseBlock if_else = 1; // required
}

message IfElseBlock {
  IfBlock case = 1;          // first condition to evaluate
  repeated IfBlock other = 2; // additional conditions
  oneof default {
    Node else_node = 3;        // executed if no condition matched
    Error error = 4;           // fail if no condition matched
  }
}

message IfBlock {
  core.BooleanExpression condition = 1;
  Node then_node = 2;
}

GateNode

Blocks workflow progress until an external condition is satisfied.
message GateNode {
  oneof condition {
    ApproveCondition approve = 1;  // wait for a boolean signal
    SignalCondition signal = 2;    // wait for a typed signal value
    SleepCondition sleep = 3;      // wait for a fixed duration
  }
}

ArrayNode

Maps a sub-node over a list of inputs with configurable parallelism. Equivalent to a fan-out / map task at the workflow level.
message ArrayNode {
  Node node = 1;                // sub-node to execute per element
  uint32 parallelism = 2;       // max concurrent sub-node instances
  uint32 min_successes = 3;     // minimum successes to mark ArrayNode successful
  float min_success_ratio = 4;  // alternative: minimum success fraction
  ExecutionMode execution_mode = 5; // MINIMAL_STATE or FULL_STATE
  DataMode data_mode = 7;       // SINGLE_INPUT_FILE or INDIVIDUAL_INPUT_FILES
  bool run_all_sub_nodes = 9;   // continue even after failure threshold
}
Use min_success_ratio instead of min_successes when the array size is not known at compile time (e.g., dynamic fan-out).

Minimal workflow spec example

The following is a minimal compiled workflow closure in JSON, representing a workflow with a single task node:
{
  "workflow": {
    "id": {
      "resourceType": "WORKFLOW",
      "project": "flytesnacks",
      "domain": "development",
      "name": "my_module.hello_world_wf",
      "version": "v1"
    },
    "metadata": {
      "onFailure": "FAIL_IMMEDIATELY"
    },
    "interface": {
      "inputs": {
        "variables": {
          "name": {
            "type": { "simple": "STRING" },
            "description": "The name to greet"
          }
        }
      },
      "outputs": {
        "variables": {
          "o0": {
            "type": { "simple": "STRING" },
            "description": "Greeting string"
          }
        }
      }
    },
    "nodes": [
      {
        "id": "start-node"
      },
      {
        "id": "end-node",
        "inputs": [
          {
            "var": "o0",
            "binding": { "promise": { "nodeId": "n0", "var": "o0" } }
          }
        ]
      },
      {
        "id": "n0",
        "metadata": {
          "name": "say_hello",
          "retries": { "minimum": 0 }
        },
        "inputs": [
          {
            "var": "name",
            "binding": { "promise": { "nodeId": "^.inputs", "var": "name" } }
          }
        ],
        "upstreamNodeIds": ["start-node"],
        "taskNode": {
          "referenceId": {
            "resourceType": "TASK",
            "project": "flytesnacks",
            "domain": "development",
            "name": "my_module.say_hello",
            "version": "v1"
          }
        }
      }
    ],
    "outputs": [
      {
        "var": "o0",
        "binding": { "promise": { "nodeId": "n0", "var": "o0" } }
      }
    ],
    "metadataDefaults": {}
  },
  "tasks": [
    {
      "id": {
        "resourceType": "TASK",
        "project": "flytesnacks",
        "domain": "development",
        "name": "my_module.say_hello",
        "version": "v1"
      },
      "type": "python-task",
      "metadata": { "runtime": { "type": "FLYTE_SDK", "version": "1.16.4", "flavor": "python" } },
      "interface": {
        "inputs": {
          "variables": {
            "name": { "type": { "simple": "STRING" } }
          }
        },
        "outputs": {
          "variables": {
            "o0": { "type": { "simple": "STRING" } }
          }
        }
      },
      "container": {
        "image": "ghcr.io/flyteorg/flytekit:py3.11-1.16.4",
        "command": [],
        "args": [
          "pyflyte-execute",
          "--inputs", "{{.input}}",
          "--output-prefix", "{{.outputPrefix}}",
          "--raw-output-data-prefix", "{{.rawOutputDataPrefix}}",
          "--resolver", "flytekit.core.python_auto_container.default_task_resolver",
          "--",
          "task-module", "my_module",
          "task-name", "say_hello"
        ],
        "resources": {
          "requests": [
            { "name": "CPU", "value": "100m" },
            { "name": "MEMORY", "value": "200Mi" }
          ]
        }
      }
    }
  ]
}

WorkflowMetadata failure policies

PolicyEnum ValueBehavior
FAIL_IMMEDIATELY0Abort all running nodes as soon as any node fails.
FAIL_AFTER_EXECUTABLE_NODES_COMPLETE1Let independent nodes complete before marking the workflow as failed.

Build docs developers (and LLMs) love