Build and edit Dify workflow DSL files...
Build, edit, and validate Dify workflow DSL (Domain-Specific Language) files for creating AI-powered automation workflows.
This skill is based on the Dify open-source platform's workflow engine, which powers both Workflow apps and Advanced Chat apps with a React Flow-based visual editor.
Dify workflows use a queue-based, event-driven architecture with:
sendBeacon for safetyisWorkflowDataLoaded flagNode Types: See references/node_types.md for complete list including:
Edge Types and Connections: See references/edge_types.md for:
Node Positioning: See references/node_positioning.md for:
Common Node Properties: All nodes support these internal properties (prefixed with _):
_runningStatus: Current execution status (running, succeeded, failed)_connectedSourceHandleIds/_connectedTargetHandleIds: Connection tracking_isSingleRun: Single execution mode for debugging_isCandidate: Phantom node during connection drag_children: Child nodes for container types (iteration, loop)_iterationLength/_iterationIndex: Iteration state tracking_loopLength/_loopIndex: Loop state tracking_retryIndex: Current retry attempt_waitingRun: Queued for execution, human-inputWorkflow Structure: See references/workflow_structure.md for complete DSL format
Edge Types: See references/edge_types.md for connection patterns and handle types
Node Positioning: See references/node_positioning.md for layout guidelines
Templates: Check assets/ for example workflows
Ask the user:
Plan the workflow structure:
Use scripts/generate_id.py to create unique node IDs:
python3 scripts/generate_id.py 5 # Generate 5 unique IDs
Or generate in Python/JavaScript:
# Python
import time
node_id = str(int(time.time() * 1000))
// JavaScript (used in Dify frontend)
const nodeId = `${Date.now()}`
Special ID patterns for container nodes:
${parentNodeId}start1736668800000, its start node ID is 1736668800000startCreate the complete YAML structure with:
Template to use: Start from assets/simple_llm_workflow.yml for basic flows
Check the workflow structure for common issues:
{{#node_id.field#}}Start β LLM β End
Use case: Basic question answering, text generation
Template: assets/simple_llm_workflow.yml
Start β Code (with fail-branch) β [Success β Aggregator] / [Fail β LLM Recovery β Retry β Aggregator] β End
Use case: Robust data processing with error recovery
Template: assets/error_handling_workflow.yml
Key points:
error_strategy: fail-branch on code nodeerror_message and error_type variablesStart β If-Else β [True β Handler A] / [False β Handler B] β Aggregator β End
Use case: Route requests based on content/type
Template: assets/conditional_workflow.yml
Key points:
true and false sourceHandlesStart β Loop β [Process Items] β Loop End β End
Use case: Iterative processing with break conditions
Key points:
loop_count for maximum iterationsbreak_conditions to exit earlyworkflow.graph.nodes array with:workflow.graph.edges connecting the new nodeworkflow.graph.nodessource, target, sourceHandle, or targetHandledata.sourceType and data.targetType to match actual node typesid to follow naming convention: {source_id}-{handle}-{target_id}-targetVariables are managed in a centralized VariablePool and use the format: {{#node_id.field_name#}}
Dify supports these variable types for type-safe data flow:
Primitive Types:
string: Text datanumber: Floating-point numbersinteger: Whole numbersboolean: true/false valuessecret: Encrypted sensitive data (API keys, passwords)Complex Types:
object: JSON objectsfile: Single file referencearray: Generic arrayarray[string]: Array of stringsarray[number]: Array of numbersarray[object]: Array of objectsarray[boolean]: Array of booleansarray[file]: Array of filesarray[any]: Array of mixed typesany: Any type (use sparingly)Special Types:
contexts: Knowledge retrieval resultsiterator: Iteration input variableloop: Loop input variableWhen using file input types (file, files, file-list), you can configure upload settings:
Default File Upload Settings:
allowed_file_upload_methods: ['local_file', 'remote_url']
max_length: 5 # Maximum number of files
allowed_file_types: ['image'] # Options: image, document, audio, video, custom
allowed_file_extensions: [] # e.g., ['.pdf', '.docx']
Upload Methods:
local_file: Direct file upload from local systemremote_url: Upload file from URLFile Type Categories:
image: Image files (JPG, PNG, GIF, etc.)document: Document files (PDF, DOCX, TXT, etc.)audio: Audio files (MP3, WAV, etc.)video: Video files (MP4, AVI, etc.)custom: Custom file types (specify extensions)Start nodes use these input types for user-facing variables:
text-input: Single-line text inputparagraph: Multi-line text inputselect: Dropdown selectionnumber: Numeric inputcheckbox: Boolean checkboxurl: URL input with validationfiles: Multiple file uploadfile: Single file uploadfile-list: Multiple file listjson: JSON input (object or array)json_object: JSON object with schema validationcontexts: Knowledge retrieval contextiterator: Iteration variableloop: Loop variableThe variable pattern regex: {{#[a-zA-Z0-9_]{1,50}(?:\.[a-zA-Z_][a-zA-Z0-9_]{0,29}){1,10}#}}
Selector structure: [node_id, variable_name, ...optional_nested_keys]
ValueSelector: Array format used in DSL (e.g., ['1732007415808', 'text'])
value_selector: ['node_id', 'field_name']{{#node_id.field_name#}}Available via sys node ID:
{{#sys.query#}} - User query/input{{#sys.files#}} - Uploaded files{{#sys.conversation_id#}} - Current conversation ID{{#sys.user_id#}} - User identifier{{#sys.dialogue_count#}} - Number of dialogue turns{{#sys.app_id#}} - Application ID{{#sys.workflow_id#}} - Workflow ID{{#sys.workflow_run_id#}} - Current execution ID{{#sys.timestamp#}} - Current timestampLLM Node:
{{#node_id.text#}} - Generated text response (type: string){{#node_id.usage#}} - Token usage information (type: object){{#node_id.reasoning_content#}} - Model reasoning (if enabled) (type: string)Agent Node:
{{#node_id.usage#}} - Token usage information (type: object)Code Node:
{{#node_id.output_name#}} - Named outputs defined in node config{{#node_id.error_message#}} - Error message (fail-branch only) (type: string){{#node_id.error_type#}} - Error type (fail-branch only) (type: string)Start Node:
{{#node_id.variable_name#}} - Input variables defined in start nodeIf-Else Node:
{{#node_id.condition_result#}} - Boolean condition resultLoop Node:
{{#node_id.output#}} - Loop output array{{#node_id.iteration#}} - Current iteration numberHTTP Request Node:
{{#node_id.body#}} - Response body (type: string){{#node_id.status_code#}} - HTTP status code (type: number){{#node_id.headers#}} - Response headers (type: object){{#node_id.files#}} - Downloaded files if response is file (type: array[file])Tool Node:
{{#node_id.text#}} - Tool output text (type: string){{#node_id.files#}} - Tool output files (type: array[file]){{#node_id.json#}} - Tool output JSON (type: array[object])Knowledge Retrieval Node:
{{#node_id.result#}} - Retrieved knowledge segments (type: array[object])Template Transform Node:
{{#node_id.output#}} - Transformed output (type: string)Question Classifier Node:
{{#node_id.class_name#}} - Classification result (type: string){{#node_id.usage#}} - Token usage information (type: object)Parameter Extractor Node:
{{#node_id.__is_success#}} - Extraction success indicator (type: number){{#node_id.__reason#}} - Extraction failure reason (type: string){{#node_id.__usage#}} - Token usage information (type: object)Variable Aggregator:
{{#node_id.output#}} - Aggregated output from merged branchesFile Object Structure (when file type is used):
name - File name (type: string)size - File size in bytes (type: number)type - File type category (type: string)extension - File extension (type: string)mime_type - MIME type (type: string)transfer_method - Transfer method used (type: string)url - File URL (type: string)related_id - Related resource ID (type: string)Knowledge Retrieval Result Structure:
{
"content": "",
"title": "",
"url": "",
"icon": "",
"metadata": {
"dataset_id": "",
"dataset_name": "",
"document_id": [],
"document_name": "",
"document_data_source_type": "",
"segment_id": "",
"segment_position": "",
"segment_word_count": "",
"segment_hit_count": "",
"segment_index_node_hash": "",
"score": ""
}
}
Environment variables (defined at app level):
env{{#env.API_KEY#}}Conversation variables (session state):
conversation{{#conversation.user_context#}}# In LLM prompt template
prompt_template:
- role: system
text: "You are a helpful assistant."
- role: user
text: "Process this input: {{#1732007415808.user_input#}}"
# In code node
variables:
- ["1732007415808", "user_input"]
- ["1732007420123", "processed_data"]
# Accessing nested object fields
text: "File name: {{#upload_node.files.name#}}"
text: "API response status: {{#http_node.status_code#}}"
Position nodes on the canvas for visual clarity:
Layout Constants (from Dify frontend):
NODE_WIDTH: 240 pixelsX_OFFSET: 60 pixels (horizontal spacing)NODE_WIDTH_X_OFFSET: 300 pixels (node width + spacing)Y_OFFSET: 39 pixelsSTART_INITIAL_POSITION: { x: 80, y: 282 }NODE_LAYOUT_HORIZONTAL_PADDING: 60 pixelsNODE_LAYOUT_VERTICAL_PADDING: 60 pixelsNODE_LAYOUT_MIN_DISTANCE: 100 pixelsContainer Node Padding:
Horizontal spacing: 300-400 pixels between connected nodes Vertical spacing:
Example positions:
Start: x=80, y=282 # Initial position
LLM: x=380, y=282 # Start + NODE_WIDTH_X_OFFSET
Code: x=680, y=282
End: x=980, y=282
For branching:
If-else: x=380, y=300
True branch: x=680, y=200
False branch: x=680, y=450
Aggregator: x=980, y=300
Container nodes (Iteration/Loop):
parentId set to container IDSee references/node_positioning.md for detailed layout patterns and formulas.
The DSL you create is rendered in the Dify visual workflow editor built with React Flow.
Nodes β Visual blocks on canvas with:
type and title fields)Edges β Bezier curves connecting nodes with:
Viewport β Canvas view settings:
viewport:
x: 0 # Pan offset X
y: 0 # Pan offset Y
zoom: 1.0 # Zoom level (0.1 to 2.0)
When your DSL is loaded into the editor:
These UI-only properties are managed by the frontend (don't include in DSL):
_hovering, _connectedNodeIsHovering: Mouse interaction state_connectedSourceHandleIds, _connectedTargetHandleIds: Computed from edges_runningStatus, _singleRunningStatus: Runtime execution state_isCandidate: Temporary phantom node during connection dragselected: Node selection stateImportant: Only include persistent properties in your DSL (id, type, title, position, configuration). Runtime UI state is computed by the editor.
Dify supports multiple error handling strategies defined in the node configuration:
1. fail-branch (recommended for code/http nodes):
error_message and error_type variablessourceHandle: "fail-branch" in edge configurationsourceHandle: "success-branch"2. default-value:
3. abort (default):
4. retry:
retry_config sectionRetry Configuration Structure:
retry_config:
max_retries: 3 # Maximum retry attempts (default: 3)
retry_interval: 100 # Interval between retries in ms (default: 100)
In node configuration:
error_strategy: fail-branch
In edges array:
# Success path
- id: code_node-success-branch-next_node-target
source: code_node_id
target: aggregator_id
sourceHandle: success-branch
targetHandle: target
# Failure path
- id: code_node-fail-branch-error_handler-target
source: code_node_id
target: error_handler_id
sourceHandle: fail-branch
targetHandle: target
Available error variables in fail-branch:
{{#node_id.error_message#}} - Human-readable error description{{#node_id.error_type#}} - Error type classificationBefore finalizing a workflow, verify:
sourceHandle values match node types:"source" (default)"true", "false", or classification label"success-branch" or "fail-branch""loop" for continuationtargetHandle is typically "target" for most nodesdata.sourceType matches the actual source node typedata.targetType matches the actual target node typeerror_strategy: fail-branch is used{{#node_id.field#}}sys prefix: {{#sys.query#}}env prefix if needederror_strategy: fail-branch have both success and fail edgeserror_strategy: default-valueloop_count and break conditionsDify categorizes nodes by their execution behavior. Understanding these types helps design correct workflows:
Execute logic and produce outputs. Most common node type.
"source" (or "success-branch"/"fail-branch" with error handling)Control flow by choosing between multiple paths based on conditions.
"true", "false"Manage nested execution contexts with iterations or loops.
"loop" for iteration/loop continuationStream outputs to users in real-time.
Serve as workflow entry points.
The following node types can produce output variables that other nodes can reference:
Note: Nodes not in this list (like if-else, end, answer) typically don't produce reusable output variables, though some may have limited internal state.
Edges can be in three states during execution:
Workflows progress through these states:
Individual nodes track their execution state with these statuses:
Important UI State Properties (runtime only, not in DSL):
_runningStatus: Current execution status_singleRunningStatus: Status when running single node_waitingRun: Node is queued for execution_retryIndex: Current retry attempt number_isSingleRun: Node is in single-run debug modeloop_count limits and clear break conditionsgenerate_id.py - Generate unique node IDs for workflowsvalidate_workflow.py - Validate workflow DSL syntax (requires PyYAML)node_types.md - Complete reference of all Dify node types with examplesworkflow_structure.md - Detailed DSL structure and format specificationsimple_llm_workflow.yml - Basic startβLLMβend templateerror_handling_workflow.yml - Template with fail-branch error handlingconditional_workflow.yml - Template with if-else branching