When Dify's built-in nodes aren't enough, Code nodes let you write Python or JavaScript logic directly in your workflow. Here's how.

When the Visual Builder Isn't Enough

Dify's drag-and-drop workflow builder covers 80% of use cases. The other 20% -- complex data transformation, calling APIs with custom auth logic, regex parsing, conditional branching based on computed values -- needs a Code node.

Code nodes let you write Python or JavaScript directly inside a Dify workflow. They're one of the most powerful and least documented features in Dify. This guide covers everything you need to use them confidently.

What Code Nodes Can Do

  • Transform or reformat data between nodes (parse JSON, manipulate strings, compute values)
  • Call external APIs with custom headers, OAuth tokens, or request signing
  • Apply conditional logic that's too complex for the built-in IF node
  • Parse and clean LLM outputs (extract structured data, strip unwanted formatting)
  • Compute scores, rankings, or aggregations across multiple inputs
Code nodes run in a sandboxed environment. They cannot access the filesystem, spawn subprocesses, import arbitrary packages (only a curated set of standard libraries are available), or make network calls unless the node is specifically set up as an HTTP tool.

Adding a Code Node

  1. In the workflow canvas, click the + button between two existing nodes.
  2. Select Code from the node type list.
  3. Choose Python 3 or JavaScript as the language.
  4. Write your function in the editor. The function must return a dict (Python) or object (JS).

The function signature

Your code must define a main() function that receives all input variables and returns an output dict. The return keys become available as variables for downstream nodes.

# Python Code node -- basic structure
def main(input_var_1: str, input_var_2: int) -> dict:
    # Process inputs
    result = input_var_1.upper()
    count = input_var_2 * 2
 
    # Return a dict -- keys become output variables
    return {
        "processed_text": result,
        "doubled_count": count,
    }
// JavaScript Code node -- same structure
async function main({ input_var_1, input_var_2 }) {
    const result = input_var_1.toUpperCase();
    const count = input_var_2 * 2;
 
    return {
        processed_text: result,
        doubled_count: count,
    };
}

Connecting Inputs and Outputs

In the Code node panel, you define which upstream variables the node receives and what keys it outputs. This is the part most tutorials skip, which causes the most frustration.

Setting up inputs

  1. In the Code node's Input Variables panel, click Add Variable.
  2. Give the variable a name (this is the parameter name in your function).
  3. Set the Type (String, Number, Array, Object).
  4. Map it to an upstream node's output by clicking the value field and selecting from the variable picker.

Setting up outputs

  1. In the Output Variables panel, add each key your function returns.
  2. Set the type for each output key.
  3. Downstream nodes can now reference these outputs via the variable picker.
If your function returns a key that isn't declared in Output Variables, Dify silently drops it. Always declare every key you return, or downstream nodes will have missing variables.

Practical Examples

Example 1: Parse an LLM output into structured fields

LLMs often return semi-structured text even when you ask for JSON. A Code node can clean this up before downstream nodes consume the data.

import json, re
 
def main(llm_output: str) -> dict:
    # Try direct JSON parse first
    try:
        data = json.loads(llm_output)
        return {"name": data.get("name", ""), "score": data.get("score", 0)}
    except json.JSONDecodeError:
        pass
 
    # Fallback: extract with regex
    name_match = re.search(r'Name:\s*(.+)', llm_output)
    score_match = re.search(r'Score:\s*(\d+)', llm_output)
    return {
        "name":  name_match.group(1).strip() if name_match else "",
        "score": int(score_match.group(1)) if score_match else 0,
    }

Example 2: Call an external API with a custom auth header

Use the HTTP Request tool node for most API calls, but when you need computed headers (e.g. HMAC signatures, time-based tokens), a Code node is the right place.

import hashlib, hmac, time
 
def main(api_key: str, api_secret: str, payload: str) -> dict:
    # Compute HMAC signature (e.g. for Stripe-style webhook verification)
    timestamp = str(int(time.time()))
    message = f"{timestamp}.{payload}"
    sig = hmac.new(
        api_secret.encode(), message.encode(), hashlib.sha256
    ).hexdigest()
 
    return {
        "auth_header": f"t={timestamp},v1={sig}",
        "timestamp": timestamp,
    }

Example 3: Transform a list of items for a downstream loop

def main(raw_items: list) -> dict:
    # Clean, deduplicate, and format a list for downstream processing
    seen = set()
    cleaned = []
    for item in raw_items:
        key = item.get("id", "").strip().lower()
        if key and key not in seen:
            seen.add(key)
            cleaned.append({
                "id": key,
                "label": item.get("name", "").title(),
                "value": float(item.get("value", 0)),
            })
    return {"items": cleaned, "count": len(cleaned)}

Debugging Code Nodes

  • Use the Run This Node button in the node panel to test with sample inputs before wiring the node into your workflow
  • Print statements do NOT produce visible output -- use return values to surface debug data
  • If your node silently fails, check that all Input Variables are correctly mapped to upstream outputs
  • Type mismatches (e.g. passing a string where the function expects a list) cause silent failures -- double-check types in the Input Variables panel
  • The execution log (accessible via the workflow's run history) shows the Code node's input and output values for each run -- use this to trace unexpected behaviour

Limitations to Know

  • Available Python packages: json, re, math, datetime, hashlib, hmac, base64, urllib -- no pip install
  • No filesystem access
  • No async in Python nodes (JavaScript nodes support async/await)
  • Maximum execution time: 10 seconds -- long-running operations will timeout
  • Code nodes cannot call other Dify workflows or agents -- use an HTTP Request node for that