openbrain
Concepts

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

TypeDescriptionColor
TEXTNatural language text (prompts, descriptions)Blue
IMAGERaster image (PNG, JPEG, WebP)Purple
VIDEOVideo file (MP4, WebM)Red
AUDIOAudio file (MP3, WAV)Orange
MASKBinary mask image (used for inpainting)Pink
3D3D model file (GLB, OBJ)Teal
NUMBERNumeric value (integer or float)Green
BOOLEANTrue/false valueYellow
STRINGRaw string (not interpreted as natural language)Cyan
JSONArbitrary JSON object or arrayGray
LORALoRA model weightsIndigo
MODELModel identifier or referenceSlate
ANYWildcard type that accepts any connectionWhite

Compatibility rules

Not all types connect only to their exact match. flow has the following compatibility rules:

ConnectionRule
MASK inputAccepts IMAGE outputs (masks are images)
STRING inputAccepts TEXT outputs (text is a string)
JSON inputAccepts NUMBER, BOOLEAN, STRING, and TEXT outputs (scalar values are valid JSON)
ANY inputAccepts any output type
ANY outputConnects to any input type
Same typeAlways 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.

On this page