Dynamic Script Node
Real Python inside your workflow — and a sandbox you shouldn't fully trust
- exception
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.
torchandnumpyare allowed; a bad script can still eat your VRAM or hang your queue. - It always reruns. The node returns
NaNfrom 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
forloop in my graph," it's the one to reach for.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| input_ports_count | INT | 20–100 | The number of input ports for this node. |
| output_ports_count | INT | 10–100 | The number of output ports for this node. |
| module_count | INT | 00–100 | Number 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_prefix | STRING | dynamic_module | Prefix 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_cache | BOOLEAN | true | Reuse 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_cache | BOOLEAN | false | Remove 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_restrictions | BOOLEAN | false | Allow importing any module. (use with caution, check the code first !!!) |
| lazy_execution | BOOLEAN | false | Execute 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'. |
| code | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| exception | * | Exception information or None. |