Workflow or Chatflow
Both app types share one canvas and one set of nodes. The docs describe most of the work as drag, connect and configure, with code only where your logic calls for it. The difference is how people use the result.
A Workflow takes an input, runs the whole flow and returns a result, so it suits report generation, data processing and batch jobs. A Chatflow puts a chat window in front: each message runs the flow before a reply goes out, so it suits assistants and guided Q&A.
They start and end on different nodes. A Workflow begins at User Input or at a Trigger, which starts it on a schedule, from a webhook or from an integration event. A Chatflow always begins at User Input, so it has no Triggers. A Chatflow must end at an Answer node. A Workflow may end at an Output node, the node that was named End before. The docs call it optional, but a branch with no Output node returns nothing to the caller.
The nodes you will use most
Every field you add to the User Input node becomes a variable that later nodes can use. In any text box, type { or / to pick a variable, and the editor writes the {{variable_name}} reference for you.
| Node | Job | What the docs say |
|---|---|---|
| User Input | Collects what a person enters | One per canvas. Short Text takes up to 256 characters. Other field types are paragraph, select, number, checkbox, JSON and files |
| LLM | Calls a model with your prompt | Temperature runs from 0, deterministic, to 1, creative. Structured output returns named fields the next node can read |
| Knowledge Retrieval | Searches your knowledge bases | Returns a result list. Set the LLM node's Context to it. Lesson 3 covers this |
| IF/ELSE | Sends the run down one branch | IF, ELIF and ELSE paths. Conditions combine with AND or OR |
| Code | Runs Python or JavaScript | The function must return a dictionary holding the declared outputs |
| HTTP Request | Calls an outside API | GET, HEAD, POST, PUT, PATCH and DELETE. Authentication, body and timeouts are set per node |
| Template | Formats text with Jinja2 | Rule-based formatting at zero token cost |
| Output or Answer | Returns the result | Output in a Workflow, Answer in a Chatflow |
Build the content generator
The docs' 30-Minute Quick Start builds a workflow that takes a draft, optional files, a voice and tone, target platforms and a language, then returns one post per platform. It runs on Dify Cloud, and the page says to follow the same steps on a self-hosted instance. The steps below condense it, in its order. A Parameter Extractor is a node that asks a model to pull structured values out of free text, and here it turns whatever a person types into a clean list of platforms.
# TASK DESCRIPTION
Parse platform names from input and output as a JSON array.
## PROCESSING RULES
- Support multiple delimiters: commas, semicolons, spaces, line breaks, "and", "&", "|", etc.
- Standardize common platform name variants (twitter/X→Twitter, insta→Instagram, etc.)
- Remove duplicates and invalid entries
- Preserve unknown but reasonable platform names
- Preserve the original language of platform names
## OUTPUT REQUIREMENTS
- Success: ["Platform1", "Platform2"]
- No platforms found: [No platforms identified. Please enter a valid platform name.]
## EXAMPLES
- Input: "twitter, linkedin" → ["Twitter", "LinkedIn"]
- Input: "x and insta" → ["Twitter", "Instagram"]
- Input: "invalid content" → [No platforms identified. Please enter a valid platform name.]- In Studio, choose Create from Blank > Workflow, name it
Multi-platform content generatorand click Create. - In the User Input node add five fields. The field
draftis a required Paragraph (max length 2048), anduser_fileis a File list for documents and images. The fieldvoice_and_toneis a Paragraph, andplatformis a required Short Text. The last one,language, is a required Select with English, 日本語 and 简体中文. - Add a Parameter Extractor. Set Input Variable to
User Input/platform, add an extract parameter namedplatformof type Array[String], mark it required and paste the instruction above into the Instruction field. - Add an IF/ELSE node with the condition
Parameter Extractor/platformcontainsNo platforms identified. Please enter a valid platform name.Put an Output node on the IF branch that returnsParameter Extractor/platform. A bad platform name now ends the run early, before tokens go on useless content. - On the ELSE branch add two List Operator nodes in parallel. Both take
User Input/user_fileas input. One filters type in Image and the other type in Doc. - After the document branch add a Doc Extractor, which turns PDF and DOCX files into plain text, because the tutorial's model cannot read them directly.
- Add an LLM node named
Integrate Info. Turn on Vision, set the image branch as the vision variable and ask it for a structured summary of the draft, the document text and the images. - Add an Iteration node. Inside it, an LLM node
Identify Stylewrites guidelines forCurrent Iteration/item, then an LLM nodeCreate Contentwrites the post with structured output holdingplatform_nameandpost_content. - On the Iteration node set the input to
Parameter Extractor/platformand the output toCreate Content/structured_output. Turn on Parallel Mode and set the maximum parallelism to 10, so the platforms are written side by side.
Format the result and run it
The Iteration node returns a raw list of platform and post pairs. A Template node turns that list into readable text with Jinja2, a templating language. A model can format output too, but the quick start warns that its results can be inconsistent, while a rule-based template costs no tokens. This is the quick start's template, without its phone emoji.
{% for item in output %}
# {{ item.platform_name }}
{{ item.post_content }}
{% endfor %}- Add a Template node after the Iteration node. Set
Iteration/outputas its input variable, name itoutputand paste the template above. - Add an Output node and set
Template/outputas its output variable. - Make sure the Checklist is clear and compare your canvas with the quick start's diagram.
- Click Test Run at the top right, fill in the fields and click Start Run. The docs suggest this draft: "We just launched a new AI writing assistant that helps teams create content 10x faster." Add the voice "Friendly and enthusiastic, but professional", the platforms "Twitter and LinkedIn" and the language English.
Code and HTTP Request nodes
A Code node covers what no preset node does. You declare input variables and output variables, and the function has to return a dictionary holding the declared outputs, like the main function in lesson 1. An output over any limit below fails the node.
Both Code and HTTP Request have Retry on failure: a failed run tries again up to 10 times, and the interval can be set up to 5000 milliseconds. Their Error Handling option defines a fallback path, so the rest of the flow can continue when one of them fails.
The HTTP Request node sets the method, URL, headers, query parameters, body and authentication in one panel. Authentication is No Auth or API Key, and API Key has Basic, Bearer and Custom subtypes. The body is JSON, Form Data, Binary or Raw Text. The response comes back as separate variables: the body, the status code, the headers, any files and the size. A Secret-type environment variable is masked in the run logs and in this node's request log.
30
items in an array[string] or array[object]
Source: Dify Docs (GitHub): Code node (read November 6, 2026)
Run and debug a workflow
You can test one node alone: select it, give it test input in its panel and click Run. The docs say Answer and End nodes don't support single node testing. End is the Output node's old name and the page does not mention the new one, so check an Output node with a whole-flow run. Whole-flow runs and single-node runs both leave records, and four tools read them.
The Variable Inspector holds the data each node produced. When you run nodes one at a time, their outputs are cached there, and you can edit most values and run a downstream node again with your edit, without rerunning anything upstream. The quick start opens the same list through View cached variables at the bottom of the canvas.
| Tool | What it shows | Use it to |
|---|---|---|
| Last run | A node's inputs, outputs, timing and any error message | Find which node failed and what it received |
| Variable Inspector | The output variables of nodes that ran. Editing a value leaves the original node's Last run unchanged | Try a different input on one node. The revert icon restores one variable and Reset all clears the cache |
| Run History: Result and Detail | Result is the final output or the error, for Workflow apps only. Detail is the original input, the final output and system metadata | Compare what a run received with what it returned |
| Run History: Tracing | Which nodes ran, in what order, how long each took and where data flowed | Find a slow step in a flow with branches or loops |
Publish and keep versions
Your working copy is the Current Draft, and users never see it. Click Publish > Publish Update and the draft becomes the Latest Version, the one users see, and you get a fresh draft. Older publishes sit under Previous Versions.
From the history list you can name a version, add release notes, delete old versions, restore one into your draft or export it with Export App. You can't delete the Current Draft or the Latest Version. Restoring replaces your current draft completely, so finish or export unsaved work first. A version export never includes the values of Secret-type environment variables. Version control exists for Workflow and Chatflow apps only.
The next lessons add a knowledge base and an agent. Lesson 4 covers publishing as a web app, an API and an embed.
Common mistakes
- Leaving a branch without an Output node. A workflow or branch with none returns no data to the caller.
- Giving two Output nodes the same variable name. The later one overwrites the earlier value.
- Ordering variables carelessly in an Answer node. It streams text up to the first variable that has no value yet, so the order inside the Answer decides what appears first.
- Asking a model for rule-based formatting that a Template node does at no token cost.
- Rerunning the whole flow to test one change, when editing the cached variable and running one node is enough.
- Typing the chat message variable by hand. The chatbot tutorial writes
{{sys.query}}while the User Input page listsuserinput.query, so pick the variable from the list your version shows. - Running Code node scripts you did not write. The sandbox can still reach other services inside your Dify deployment.
- Seeing every Code node fail with "network is disabled, please enable it in the configuration". On a self-hosted install,
SANDBOX_ENABLE_NETWORKis set to false. The default is true.
Try it yourself
- Enter
ohhhhhhas the Target Platform and check that the IF branch returns the error message instead of posts. - After a run, open the Variable Inspector, edit the platform list to a single platform and run the Iteration node alone.
- Publish the flow, change one prompt and publish again. Open the history, name both versions and restore the first into your draft.
Next
Lesson 3 adds a knowledge base to a flow, so an LLM node can answer from your own documents. It rests on the idea behind RAG, and that lesson is worth reading first if retrieval is new to you.
Check yourself
Which node must end a Chatflow?
Show answer
B. Answer The docs list Answer as the required end of a Chatflow. Output is the optional end of a Workflow.
One branch of a Workflow has no Output node. What does the caller get from that branch?
Show answer
C. No data The Output page says a workflow or branch without an Output node returns no data to the caller.
You want to see how the Template node reacts to a different list without paying for the model calls again. What do you do?
Show answer
A. Edit the cached variable in the Variable Inspector and run that node Cached outputs can be edited in the Variable Inspector, and a downstream node then runs with the edited value without rerunning upstream nodes.
A Code node returns a string of 500,000 characters with the default settings. What happens?
Show answer
D. The node fails The Code page says an output that exceeds a limit fails the node, and the default string limit is 400,000 characters.
Frequently asked questions
What is the difference between a Dify workflow and a chatflow?
A Workflow gets its inputs once and returns whatever its Output nodes hold, which suits an API call or a scheduled job. A Chatflow answers each message of a conversation and can keep conversation variables between turns, which only Chatflows support.
How do I debug a Dify workflow?
Open the failing node's Last run and compare what it received with what you expected. Fix the upstream value in the Variable Inspector, run just that node again, and read Tracing in Run History if the trouble is a slow step.
Can I use Python in a Dify workflow?
Yes, with a Code node. Python includes standard libraries such as json, math, datetime and re, and the docs also show importing numpy and pandas. JavaScript works the same way.
Can I call a Dify workflow from my own code?
Yes. A workflow that starts from User Input can be published as a web app or exposed through an API. The names of its Output variables become the keys of the outputs object in the API response. Lesson 4 covers the API key.
Sources
- Dify Docs (GitHub): Workflow & Chatflow https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/build/workflow-chatflow.mdx
- Dify Docs (GitHub): 30-Minute Quick Start https://github.com/langgenius/dify-docs/blob/main/en/quick-start.mdx
- Dify Docs (GitHub): User Input node https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/nodes/user-input.mdx
- Dify Docs (GitHub): LLM node https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/nodes/llm.mdx
- Dify Docs (GitHub): Knowledge Retrieval node https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/nodes/knowledge-retrieval.mdx
- Dify Docs (GitHub): If-Else node https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/nodes/ifelse.mdx
- Dify Docs (GitHub): Code node https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/nodes/code.mdx
- Dify Docs (GitHub): HTTP Request node https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/nodes/http-request.mdx
- Dify Docs (GitHub): Answer node https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/nodes/answer.mdx
- Dify Docs (GitHub): Output node https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/nodes/output.mdx
- Dify Docs (GitHub): Single Node https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/debug/step-run.mdx
- Dify Docs (GitHub): Variable Inspector https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/debug/variable-inspect.mdx
- Dify Docs (GitHub): Run History https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/debug/history-and-logs.mdx
- Dify Docs (GitHub): Version Control https://github.com/langgenius/dify-docs/blob/main/en/self-host/use-dify/build/version-control.mdx
