Handle Types
The type system that validates connections between nodes.
Handle Types
Every input and output handle on a node has a type. The type system prevents invalid connections and ensures data flows correctly through the graph.
Available types
| Type | Description | Color |
|---|---|---|
TEXT | Natural language text (prompts, descriptions) | Blue |
IMAGE | Raster image (PNG, JPEG, WebP) | Purple |
VIDEO | Video file (MP4, WebM) | Red |
AUDIO | Audio file (MP3, WAV) | Orange |
MASK | Binary mask image (used for inpainting) | Pink |
3D | 3D model file (GLB, OBJ) | Teal |
NUMBER | Numeric value (integer or float) | Green |
BOOLEAN | True/false value | Yellow |
STRING | Raw string (not interpreted as natural language) | Cyan |
JSON | Arbitrary JSON object or array | Gray |
LORA | LoRA model weights | Indigo |
MODEL | Model identifier or reference | Slate |
ANY | Wildcard type that accepts any connection | White |
Compatibility rules
Not all types connect only to their exact match. flow has the following compatibility rules:
| Connection | Rule |
|---|---|
MASK input | Accepts IMAGE outputs (masks are images) |
STRING input | Accepts TEXT outputs (text is a string) |
JSON input | Accepts NUMBER, BOOLEAN, STRING, and TEXT outputs (scalar values are valid JSON) |
ANY input | Accepts any output type |
ANY output | Connects to any input type |
| Same type | Always compatible |
All other cross-type connections are rejected. The editor shows visual feedback when you drag a connection — compatible handles highlight, incompatible handles dim.
Handle definition
Handles are declared in a plugin's NodeDef:
interface HandleDef {
id: string; // Unique handle identifier within the node
direction: "input" | "output";
type: HandleType; // One of the 13 types above
label: string; // Display label
required?: boolean; // Whether this input must be connected (default: false)
min?: number; // Minimum instances for expandable handles
max?: number; // Maximum instances for expandable handles
collectAs?: "array"; // Collect multiple connections into an array
}Example
const handles: HandleDef[] = [
{
id: "prompt",
direction: "input",
type: "TEXT",
label: "Prompt",
required: true,
},
{
id: "image",
direction: "input",
type: "IMAGE",
label: "Reference Image",
},
{
id: "output",
direction: "output",
type: "IMAGE",
label: "Image",
},
];Dynamic handles
Some nodes support a variable number of inputs or outputs. These are expandable handles controlled by min, max, and the node's handleCounts data.
For example, an image composite node might define:
{
id: "layer",
direction: "input",
type: "IMAGE",
label: "Layer",
min: 2,
max: 10,
collectAs: "array",
}This creates a handle that starts with 2 input slots and can expand up to 10. The user adds or removes slots in the editor. When the node executes, all connected layer values are collected into an array:
// Input received by the step function
{
layer: [
"https://r2.example.com/image-1.webp",
"https://r2.example.com/image-2.webp",
"https://r2.example.com/image-3.webp",
]
}The handleCounts field on the node's data tracks how many instances of each expandable handle currently exist:
{
handleCounts: {
"layer": 3 // Currently showing 3 layer inputs
}
}Type checking at runtime
During execution, the engine does not re-validate types — validation happens at connection time in the editor. The step function receives whatever values flow through the edges. This means the type system is a design-time aid, not a runtime enforcement mechanism.
If you are building workflows via the API, ensure your edge connections respect the compatibility rules above to avoid unexpected runtime behavior.