ComfyUI Node

Dynamic Script Node

Real Python inside your workflow — and a sandbox you shouldn't fully trust

By inkbottle-9·Created 8 months ago·Updated 12 days ago· 1
Dynamic Script Node
    • exception
    input_ports_count2
    output_ports_count1
    module_count0
    module_name_prefixdynamic_module
    use_module_cachetrue
    clear_module_cachefalse
    remove_import_restrictionsfalse
    lazy_executionfalse
    code

    This is the node the whole comfyui_dynamic pack exists for. The other five nodes are quality-of-life; this one is a different category - a full Python interpreter running inside your workflow graph. When you hit the thing a node graph just can't express cleanly - string surgery, JSON wrangling, filename generation, math that would take eleven nodes, calling numpy or torch directly - DynamicScriptNode is the escape hatch.

    The honest alternative is rgthree's Power Puter, which evaluates Python-ish expressions against a strict allowlist. That's the right tool when a one-liner will do. This node is a much bigger hammer: it runs arbitrary Python, with an import allowlist instead of a sandbox. You reach for it when Power Puter isn't enough and you'd otherwise be writing a custom node from scratch.

    How it works

    You write code in the code box. The node hands you two magic names, inputs and outputs, both plain Python lists. Whatever you stuff into outputs[i] comes out the matching dynamic output port:

    import json
    
    data = json.loads(inputs[0])          # whatever you wired into input_0
    outputs[0] = data["title"]            # comes out output_0
    outputs[1] = len(data.get("tags", []))
    

    input_ports_count and output_ports_count dial how many ports exist (0–100 each). There's always a fixed exception output: None on success, or a tuple of (exception type, value, traceback, traceback lines, joined traceback string) when your script blows up - handy for wiring into a Display Any node to see the error on canvas instead of squinting at the terminal.

    The sandbox, and the warning you should read

    By default the node runs in a restricted mode: open, eval, exec, compile, input, globals and friends are stripped from your builtins, and import is replaced with a whitelist importer. The allowlist is generous - math, json, re, pathlib, itertools, numpy, pandas, torch, cv2, PIL and more are all importable - but it's not a security boundary, it's a footgun reducer. Flip remove_import_restrictions and the node can import os and run literally anything, which is why the frontend shows a bilingual "check this code" warning when you do.

    Take the author's own warning seriously: the code can come from other nodes, not just your typing, so a workflow someone shares can smuggle code in. If you didn't write it, review it before running - the pack's own docs suggest asking an AI to check it.

    Two more inputs matter. module_count + module_name_prefix (default dynamic_module) treat the first N input ports as module code: each is compiled into an importable module named {prefix}__{i}, so your main script can import dynamic_module__0. And lazy_execution only reruns the script when an input value changes - turn it on only for pure functions, because it skips execution when inputs look unchanged.

    Installing it

    The whole pack is zero-dependency, so this is the whole install:

    cd ComfyUI/custom_nodes
    git clone https://github.com/inkbottle-9/comfyui_dynamic.git
    

    Restart ComfyUI, or skip the terminal entirely: ComfyUI Manager → Install Custom Nodes → search comfyui_dynamic.

    Where people get burned

    • Refreshing the node can wipe your code. The README says it in bold. Don't keep your scripts in the code box - write them in VS Code, save to disk, and feed them in through a DynamicLoadTextFileNode (same pack) or a multiline string node.
    • Safe mode still lets you shoot yourself. Restricted builtins ≠ safe. torch and numpy are allowed; a bad script can still eat your VRAM or hang your queue.
    • It always reruns. The node returns NaN from its change-detection, so it executes on every queue run - and marks everything downstream dirty too. In a big workflow that's a caching cost, not a bug.
    • Small pack, honest bugs. This is a solo, LGPL-licensed side project with a small community footprint; the author openly says it may have bugs. Don't build your whole production pipeline on it - but for "I need a real for loop in my graph," it's the one to reach for.
    Categorydynamic/script

    Inputs (9)

    NameTypeDefaultDescription
    input_ports_countINT20–100The number of input ports for this node.
    output_ports_countINT10–100The number of output ports for this node.
    module_countINT00–100Number of leading dynamic inputs to treat as user module code. These inputs will be compiled into importable modules before the main script runs. The actual script inputs start from input_{module_count}, but you can still access the input module code by inputs list in code
    module_name_prefixSTRINGdynamic_modulePrefix for auto-generated module names. The i-th module will be named {prefix}__{i}, then you can import them in your code. Note that the module name is shared across nodes.
    use_module_cacheBOOLEANtrueReuse already-compiled user modules if their source code has not changed. This skips recompilation and speeds up execution. Modules are cached in sys.modules and persist until ComfyUI restarts or 'clear_cached_module' enabled.
    clear_module_cacheBOOLEANfalseRemove all dynamically registered modules used by this node from sys.modules after finishes executing, regardless of success or failure. This forces full recompilation on the next run and ensures no stale module state remains. You can also use function 'clear_module_cache(str|None)' to clear specific|all cached modules, and function 'get_module_cache()' to get cached module names (return a set).
    remove_import_restrictionsBOOLEANfalseAllow importing any module. (use with caution, check the code first !!!)
    lazy_executionBOOLEANfalseExecute the code lazily. Note: Enable this option only when the script executed by this node is a pure function (output depends solely on the input; in other words, the same input always produces the same output). When this option is enabled, the node will re-execute only when the value at its input changes. Warning: reading from or writing to 'cache' breaks the pure-function assumption, do not enable this option if your script uses 'cache'.
    codeSTRING

    Outputs (1)

    NameTypeDescription
    exception*Exception information or None.