Skip to main content

What are Nodes and Edges?

Nodes and edges are the fundamental building blocks of all Flowise flows. Together, they form a visual graph that represents your AI workflow.
  • Nodes: Individual components that perform specific functions (LLMs, vector stores, tools, etc.)
  • Edges: Connections between nodes that define how data flows through your system
Flowise uses ReactFlow under the hood to provide the visual canvas interface for building with nodes and edges.

Nodes

What is a Node?

A node is a self-contained component that:
  • Accepts inputs (data, configurations, credentials)
  • Performs a specific operation
  • Produces outputs for other nodes

Node Categories

Flowise includes 20+ node categories:
agentflow/        Multi-agent orchestration
agents/           Agent executors and tools
analytic/         Usage tracking and monitoring
cache/            Response caching
chains/           LangChain chains
chatmodels/       Chat-based LLMs
documentloaders/  File and data ingestion
embeddings/       Text embedding models
engine/           Query engines
graphs/           Graph databases
llms/             Language models
memory/           Conversation memory
moderation/       Content filtering
multiagents/      Multi-agent systems (V1)
outputparsers/    Response formatting
prompts/          Prompt templates
recordmanager/    Duplicate detection
responsesynthesizer/ Response generation
retrievers/       Document retrieval
sequentialagents/ Sequential workflows

Node Structure

Every node has the following structure:
{
  id: string              // Unique identifier (e.g., "chatOpenAI_0")
  type: string            // Node type for React Flow
  position: {             // Canvas position
    x: number,
    y: number
  },
  data: {                 // Node-specific data
    id: string,
    name: string,         // Node type name (e.g., "chatOpenAI")
    label: string,        // Display name
    version: number,      // Node version
    type: string,         // Category
    category: string,     // Subcategory
    description: string,
    baseClasses: string[],
    
    // Input configuration
    inputAnchors: Anchor[],
    inputParams: Parameter[],
    
    // Output configuration
    outputAnchors: Anchor[],
    
    // State
    selected: boolean,
    tags: string[]
  }
}

Input Anchors

Input anchors define connections from other nodes:
{
  id: string,
  name: string,
  label: string,
  type: string,           // Expected data type
  optional: boolean,
  list: boolean,          // Accepts multiple connections
  description: string
}
Example: Retrieval Chain Input Anchors
inputAnchors: [
  {
    name: "model",
    label: "Language Model",
    type: "BaseChatModel",
    optional: false
  },
  {
    name: "vectorStore",
    label: "Vector Store",
    type: "VectorStore",
    optional: false
  },
  {
    name: "memory",
    label: "Chat Memory",
    type: "BaseMemory",
    optional: true
  }
]

Input Parameters

Input parameters are configurable values:
{
  name: string,
  label: string,
  type: string,           // "string" | "number" | "boolean" | "options" | etc.
  default: any,
  optional: boolean,
  additionalParams: boolean,  // Hidden in "Additional Parameters" section
  description: string,
  options: Array<{        // For dropdown fields
    label: string,
    name: string,
    description: string
  }>,
  rows: number,           // For text areas
  placeholder: string
}
Example: OpenAI Node Parameters
inputParams: [
  {
    name: "modelName",
    label: "Model Name",
    type: "options",
    options: [
      { label: "gpt-4", name: "gpt-4" },
      { label: "gpt-3.5-turbo", name: "gpt-3.5-turbo" }
    ],
    default: "gpt-3.5-turbo"
  },
  {
    name: "temperature",
    label: "Temperature",
    type: "number",
    default: 0.7,
    optional: true,
    additionalParams: true
  },
  {
    name: "maxTokens",
    label: "Max Tokens",
    type: "number",
    optional: true,
    additionalParams: true
  }
]

Output Anchors

Output anchors define what a node produces:
{
  id: string,
  name: string,
  label: string,
  type: string,           // Output data type
  description: string
}
Example: ChatOpenAI Output
outputAnchors: [
  {
    name: "output",
    label: "ChatOpenAI",
    type: "ChatOpenAI | BaseChatModel | BaseLanguageModel",
    description: "OpenAI chat model instance"
  }
]

Node Versioning

Nodes have version numbers to track updates:
// Version check logic from source
const componentNode = canvas.componentNodes.find(
  (nd) => nd.name === data.name
)

if (!data.version) {
  // Warning: "Node outdated. Update to latest version X.X"
} else if (data.version && componentNode.version > data.version) {
  // Warning: "Node version X outdated. Update to version Y"
}
Outdated nodes display a warning icon. Always update to the latest version for bug fixes and new features.

Node UI Components

The CanvasNode.jsx component renders:
  1. Header: Node icon, label, and action buttons
  2. Inputs Section: Input anchors and visible parameters
  3. Additional Parameters Button: For advanced configuration
  4. Output Section: Output anchors
// Node tooltip actions
<NodeTooltip>
  <IconButton title="Duplicate" onClick={() => duplicateNode(data.id)} />
  <IconButton title="Delete" onClick={() => deleteNode(data.id)} />
  <IconButton title="Info" onClick={() => showNodeInfo()} />
</NodeTooltip>

Edges

What is an Edge?

An edge connects the output of one node to the input of another, enabling data flow.

Edge Structure

{
  id: string,             // Auto-generated unique ID
  source: string,         // Source node ID
  target: string,         // Target node ID
  sourceHandle: string,   // Specific output anchor ID
  targetHandle: string,   // Specific input anchor ID
  type: string,           // Edge type (usually "buttonedge")
  data: {                 // Optional edge data
    label: string
  }
}
Example Edge:
{
  "id": "chatOpenAI_0-conversationalRetrievalQAChain_0",
  "source": "chatOpenAI_0",
  "target": "conversationalRetrievalQAChain_0",
  "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI",
  "targetHandle": "conversationalRetrievalQAChain_0-input-model-BaseChatModel",
  "type": "buttonedge"
}

Edge Types

Flowise uses custom edge types:

ButtonEdge

The default edge with a delete button:
// From ButtonEdge.jsx
const ButtonEdge = ({ id, sourceX, sourceY, targetX, targetY }) => {
  const [edgePath, edgeCenterX, edgeCenterY] = getBezierPath({
    sourceX, sourceY, targetX, targetY
  })
  
  return (
    <>
      <path className="react-flow__edge-path" d={edgePath} />
      <foreignObject
        x={edgeCenterX - 20}
        y={edgeCenterY - 20}
        width={40}
        height={40}
      >
        <button onClick={() => deleteEdge(id)}>
          <IconX />
        </button>
      </foreignObject>
    </>
  )
}

Creating Edges

Edges are created by:
  1. Drag from output anchor to input anchor
  2. Type validation: Flowise checks if types are compatible
  3. Connection rules: Some inputs accept only one connection, others accept multiple
// Connection validation
if (inputAnchor.list === false && existingConnections.length > 0) {
  // Remove existing connection before creating new one
  deleteEdge(existingConnections[0].id)
}

Edge Labels

Edges can display labels for clarity:
<EdgeText
  x={sourceX + 10}
  y={sourceY + 10}
  label={data.label}
  labelStyle={{ fill: 'black' }}
  labelBgStyle={{ fill: 'transparent' }}
/>

Type System

Flowise uses a type system to validate node connections:

Base Types

  • BaseLLM: Base language model
  • BaseChatModel: Chat-based language model
  • BaseLanguageModel: Any language model
  • VectorStore: Vector database
  • Embeddings: Embedding model
  • BaseRetriever: Document retriever
  • BaseMemory: Conversation memory
  • Tool: Agent tool
  • Document: Document object

Type Compatibility

Connections are valid if:
// Pseudo-code for type checking
if (
  outputType === inputType ||
  inputType.includes(outputType) ||
  outputType.includes(inputType)
) {
  // Connection allowed
}
Example:
// ✅ Valid: ChatOpenAI → BaseChatModel input
output: "ChatOpenAI | BaseChatModel"
input: "BaseChatModel"

// ❌ Invalid: ChatOpenAI → VectorStore input
output: "ChatOpenAI"
input: "VectorStore"

Flow Execution

Execution Order

Flowise determines execution order by analyzing the graph:
  1. Start nodes: Nodes with no incoming edges
  2. Dependency resolution: Execute nodes only after their inputs are ready
  3. Parallel execution: Independent nodes run concurrently
  4. Final nodes: Nodes with no outgoing edges
Execution order:
  1. Parallel: A, B, F, H (no dependencies)
  2. C (depends on A)
  3. D (depends on B and C)
  4. E (depends on D)
  5. G (depends on E, F, H) - final node

Data Flow

Data passes through edges as JavaScript objects:
// Simplified flow
const documentLoaderOutput = await documentLoader.load()
const splitterOutput = await textSplitter.split(documentLoaderOutput)
const vectorStore = await createVectorStore(embeddingsOutput, splitterOutput)
const retriever = vectorStore.asRetriever()
const response = await qaChain.invoke({
  model: chatModelOutput,
  retriever: retriever,
  memory: memoryOutput,
  question: userInput
})

Working with Nodes and Edges

Adding Nodes

// From the UI
1. Click "Add Nodes" button
2. Search or browse node categories
3. Click node to add to canvas
4. Configure node parameters

Connecting Nodes

// Drag connection
1. Click and hold on output anchor (right side)
2. Drag to target input anchor (left side)
3. Release to create edge
4. Click X button on edge to delete

Duplicating Nodes

// Preserves configuration, creates new ID
duplicateNode(nodeId) {
  const node = nodes.find(n => n.id === nodeId)
  const newNode = {
    ...node,
    id: `${node.data.name}_${counter}`,
    position: {
      x: node.position.x + 50,
      y: node.position.y + 50
    }
  }
  addNode(newNode)
}

Deleting Nodes

// Also deletes connected edges
deleteNode(nodeId) {
  // Remove node
  nodes = nodes.filter(n => n.id !== nodeId)
  
  // Remove connected edges
  edges = edges.filter(e => 
    e.source !== nodeId && e.target !== nodeId
  )
}

Advanced Concepts

Conditional Nodes

Some nodes support conditional logic:
// IF-THEN node example
if (condition === "sentiment_positive") {
  routeTo(positiveResponseNode)
} else {
  routeTo(escalationNode)
}

Loop Nodes

Create iterative workflows:
// Retry logic
for (let attempt = 0; attempt < maxRetries; attempt++) {
  result = await processNode.execute()
  if (result.success) break
}

Custom Nodes

Developers can create custom nodes:
// Custom node template
class CustomNode implements INode {
  label = 'My Custom Node'
  name = 'customNode'
  version = 1
  type = 'CustomNode'
  icon = 'custom.svg'
  category = 'Custom'
  
  inputs = [/* ... */]
  outputs = [/* ... */]
  
  async init(nodeData, input) {
    // Node logic
    return output
  }
}

Best Practices

Node Organization

  • Group related nodes together on the canvas
  • Use consistent naming conventions
  • Add descriptive labels to complex nodes
  • Keep flows readable by avoiding edge crossings

Performance

  • Minimize sequential dependencies
  • Use caching nodes for repeated operations
  • Choose appropriate models for each node
  • Monitor node execution times

Maintainability

  • Update nodes to latest versions regularly
  • Document complex node configurations
  • Use variables for repeated values
  • Test flows after node updates

Troubleshooting

Connection Not Working

  • Check type compatibility between output and input
  • Verify node versions are current
  • Ensure credentials are configured (for API nodes)
  • Check for missing required parameters

Node Execution Errors

  • Review node-specific error messages
  • Verify input data format
  • Check rate limits for API nodes
  • Validate credentials and API keys

Edge Deleted Automatically

  • Node type mismatch after update
  • Input anchor changed in node version
  • Validation rule prevents connection
Check browser console (F12) for detailed error messages when debugging node and edge issues.

Build docs developers (and LLMs) love