What is a Node?
A Node is a TypeScript class that:- Extends the base
Nodeclass - Is decorated with
@defineNodeto provide metadata - Has inputs (data it receives) decorated with
@Input - Has outputs (data it produces) decorated with
@Output - Contains business logic in the
execute()method
Anatomy of a Node
Node Metadata
The@defineNode decorator provides metadata about the node:
Unique identifier for the node type (e.g.,
'math.add', 'http.request')Human-readable name displayed in the UI
Category for organizing nodes in the palette
Optional description of what the node does
Inputs
Inputs are defined using the@Input decorator:
Input Options
The data type:
'string', 'number', 'boolean', 'any', or custom typesDisplay name for the input port
Default value if no connection is made
Whether this input must be connected
Description of the input’s purpose
Outputs
Outputs are defined using the@Output decorator:
Output Options
The data type being output
Display name for the output port
Description of the output
Conditional Nodes
Conditional nodes enable branching logic in workflows by implementing theIConditionalNode interface:
The IConditionalNode Interface
evaluateCondition() which returns the name of the output port that should execute. The execution engine uses this to determine which branch to follow.
How Branches Work
- The conditional node executes normally (via
execute()method) - The execution engine calls
evaluateCondition()to get the active branch - Only nodes connected to the active output port execute
- Other branches are skipped entirely
Dynamic Outputs
Some conditional nodes generate outputs dynamically based on configuration:Built-in Conditionals
CrystalFlow includes IfNode and SwitchNode for common branching patterns
Custom Conditionals
Implement IConditionalNode to create custom branching logic
Properties
Properties are static configuration values (not connected to other nodes):Properties vs Inputs
Properties vs Inputs
- @Property: Static configuration shown in properties panel (not connected)
- @Input: Dynamic data flow connections via handles
- @Output: Computed results generated during execution
The execute() Method
Theexecute() method contains the node’s business logic:
Execution Rules
Synchronous or Async -
execute() can be sync or asyncRead from inputs - Access input values as instance properties
Write to outputs - Set output values before method returns
No side effects - Avoid modifying external state when possible
Async Execution
Node Lifecycle
- Validation - Inputs are validated before execution
- Execution - The
execute()method runs - State Update - Node state is updated (Success/Error)
- Output Propagation - Outputs are passed to connected nodes
Node States
Idle
Initial state, not yet executed
Success
Executed successfully
Error
Execution failed with an error
Type Safety
CrystalFlow uses TypeScript for type safety:Node Categories
Organize your nodes into logical categories:Input
Data sources (user input, files, APIs)
Processing
Transform and manipulate data
Output
Display results, save files, send data
Flow Control
Conditional branching and decision making
Logic
Boolean operations and comparisons
Math
Mathematical operations
String
String manipulation
Data
Data transformation and filtering
Example Nodes
Data Processing Node
HTTP Request Node
Best Practices
Keep nodes focused
Keep nodes focused
Each node should do one thing well. Split complex logic into multiple nodes.
Validate inputs
Validate inputs
Check input values in execute() and throw descriptive errors for invalid data.
Use descriptive names
Use descriptive names
Use clear, descriptive names for types, labels, and variables.
Document with descriptions
Document with descriptions
Add description fields to explain what inputs, outputs, and properties do.
Handle errors gracefully
Handle errors gracefully
Use try-catch blocks and throw meaningful errors.