FlowDrop Docs

Port system & data types

Node port definitions, built-in data types, compatibility rules, dynamic ports, and gateway branches.

Ports are the connection points on nodes. Each port has a data type that determines which other ports it can connect to and how the connection renders on the canvas.

NodePort

Every node declares its inputs and outputs as an array of NodePort objects:

interface NodePort {
  id: string;
  name: string;
  type: 'input' | 'output' | 'metadata';
  dataType: string;
  required?: boolean;
  description?: string;
  defaultValue?: unknown;
  schema?: object;
}
FieldTypeDescription
idstringUnique port identifier within the node (e.g., "text", "trigger", "tool").
namestringDisplay name shown next to the port handle.
typestringPort direction: "input", "output", or "metadata".
dataTypestringData type ID — determines color and connection compatibility.
requiredbooleanWhether a connection to this port is required for execution.
descriptionstringTooltip text explaining the port's purpose.
defaultValueunknownDefault value when no connection is made.
schemaobjectJSON Schema that narrows the port's data type for this one port. Most ports omit it and inherit the data type's schema.

Example

{
  "inputs": [
    {
      "id": "content",
      "name": "Content",
      "type": "input",
      "dataType": "string",
      "required": true,
      "description": "Text content to process"
    },
    {
      "id": "trigger",
      "name": "Trigger",
      "type": "input",
      "dataType": "trigger",
      "required": false
    }
  ],
  "outputs": [
    {
      "id": "result",
      "name": "Result",
      "type": "output",
      "dataType": "json",
      "description": "Processed output data"
    }
  ]
}

Built-in Data Types

FlowDrop ships with 21 built-in data types, each with a distinct color on the canvas:

Basic Types

IDNameCategoryDescription
triggerTriggerbasicControl flow of the workflow
stringStringbasicText data
numberNumbernumericNumeric data
booleanBooleanlogicalTrue/false values

Collection Types

IDNameDescription
arrayArrayOrdered list of items
string[]String ArrayArray of strings
number[]Number ArrayArray of numbers
boolean[]Boolean ArrayArray of true/false values
json[]JSON ArrayArray of JSON objects
file[]File ArrayArray of files
image[]Image ArrayArray of images

Complex Types

IDNameDescription
jsonJSONJSON structured data

File & Media Types

IDNameDescription
fileFileFile data
imageImageImage data
audioAudioAudio data
videoVideoVideo data

Special Types

IDNameDescription
toolToolTool interface for agent connections
urlURLWeb address
emailEmailEmail address
dateDateDate value
datetimeDateTimeDate and time value
timeTimeTime value

Your backend can extend this list by returning additional data types from the /port-config API endpoint.

Port Data Type Configuration

Each data type is defined by a PortDataTypeConfig:

interface PortDataTypeConfig {
  id: string;
  name: string;
  description?: string;
  color: string; // CSS color value or CSS variable
  category?: string; // Grouping: "basic", "numeric", "collection", etc.
  aliases?: string[]; // Alternative names for this data type
  enabled?: boolean; // Whether this type is active
  schema?: PortSchema; // JSON Schema for the values this type carries
}

Data type schemas

A data type can declare the shape of the values it carries. The editor reads that schema to offer the fields inside a value, so an author writing a template can reach message or retryable on an error port instead of only the port itself.

{
  "dataTypes": [
    {
      "id": "error",
      "name": "Error",
      "color": "var(--fd-node-red)",
      "category": "complex",
      "schema": {
        "type": "object",
        "properties": {
          "message": { "type": "string", "description": "The failure, in one sentence." },
          "code": { "type": "string", "description": "A machine-readable code, where the failing path publishes one." },
          "node_id": { "type": "string", "description": "The node instance that failed." },
          "retryable": { "type": "boolean", "description": "Whether a later attempt could succeed." }
        }
      }
    }
  ]
}

Every port whose dataType is error now offers those four fields — the schema is declared once, on the type, and no port restates it. See Template variables for how the fields are named.

A schema is optional. A data type with no schema is a lane and nothing more: it still gets a color, a badge, and compatibility gating, which is often all you want. Naming a type is useful on its own.

Compatibility never compares schemas. An order port accepts an order port because both spell order, not because two schemas were found to match — see Compatibility rules.

A schema describes what a value carries; nothing validates a value against it at run time.

Narrowing a schema for one port

A single port can set its own schema to be more specific than its data type's. That takes precedence for that port only, and every other port on the type keeps the type's schema. Reach for it when one port carries a known subset of a broad type — not to restate the type's own shape.

{
  "id": "result",
  "name": "Result",
  "type": "output",
  "dataType": "json",
  "schema": {
    "type": "object",
    "properties": {
      "title": { "type": "string" },
      "description": { "type": "string" }
    }
  }
}

Compatibility Rules

By default, ports connect only when their data types match exactly (e.g., string to string).

You can add custom compatibility rules to allow cross-type connections:

interface PortCompatibilityRule {
  from: string; // Source data type ID
  to: string; // Target data type ID
  description?: string;
}

For example, to allow string ports to connect to json inputs:

{
  "compatibilityRules": [
    {
      "from": "string",
      "to": "json",
      "description": "Strings can be parsed as JSON"
    }
  ]
}

Rules are configured via the /port-config API endpoint.

Dynamic Ports

Nodes can let users create additional ports at runtime through special config properties. When dynamicInputs or dynamicOutputs appear in a node's config, the editor creates port handles dynamically.

interface DynamicPort {
  name: string; // Port identifier (used in handle IDs)
  label: string; // Display label
  description?: string;
  dataType: string; // Data type for color and compatibility
  required?: boolean;
}

Example: Dynamic Input Ports

In the node's configSchema, declare a dynamicInputs property:

{
  "type": "object",
  "properties": {
    "dynamicInputs": {
      "type": "array",
      "title": "Custom Inputs",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "title": "Port ID" },
          "label": { "type": "string", "title": "Display Name" },
          "dataType": { "type": "string", "title": "Data Type", "default": "json" }
        },
        "required": ["name", "label"]
      }
    }
  }
}

When a user adds entries, the editor creates matching input handles. The same pattern works for dynamicOutputs.

Gateway Branches

Gateway nodes use branches in config to create conditional output paths. Each branch becomes an output port handle.

interface Branch {
  name: string; // Unique identifier (used as handle ID)
  label?: string; // Display label (defaults to name)
  description?: string;
  value?: string; // Optional value for switch matching
  condition?: string; // Condition expression
  isDefault?: boolean; // Fallback branch
}

Example

{
  "branches": [
    {
      "name": "success",
      "label": "Success",
      "condition": "status === 200"
    },
    {
      "name": "error",
      "label": "Error",
      "isDefault": true
    }
  ]
}

Each branch creates an output handle: {nodeId}-output-success, {nodeId}-output-error, etc. Edges connect from these handles to downstream nodes.

Handle ID Format

All port handles — static, dynamic, and branch — follow the same naming convention:

{nodeId}-{direction}-{portId}

Examples:

  • text_input.1-output-text — static output port
  • merger.1-input-extra_data — dynamic input port
  • router.1-output-success — gateway branch output

This format is used in edge sourceHandle and targetHandle fields.

Next Steps

On this page