ComfyUI loads every custom node in one Python process. When multiple nodes each run pip install -r requirements.txt into the shared environment, version conflicts are painful to debug.
This tool solves that by building a self-contained ComfyUI-loadable package folder: the node's Python source is compiled with Nuitka into a .so/.pyd extension, and all its pip dependencies are copied under a private _vendor tree — completely isolated from whatever the host has installed.
pack.py takes any custom node directory and:
- Installs
requirements.txtinto an isolated build folder viapip --target - Auto-discovers every top-level package that landed there (no manual mapping needed)
- Rewrites imports in the node source using the Python AST —
from PIL import Imagebecomesfrom my_node._vendor.PIL import Image - Compiles the rewritten source with Nuitka (
--module) - Assembles
dist/<package_name>/ready forComfyUI/custom_nodes/
Heavy packages (torch, numpy, CUDA) are never vendored — those stay on the host.
dist/<package_name>/
__init__.py
nodes.cpython-3xx-<platform>.so # compiled node module
_vendor/
__init__.py
PIL/ # vendored Pillow
humanize/
slugify/
... # all transitive deps are vendored automatically
git clone https://github.com/ashish-aesthisia/ComfyUI-Node-Packer
cd ComfyUI-Node-PackerThat's it. No venv, no pip install needed. On the first run pack.py detects that nuitka is missing, creates a .tool_env/ venv next to itself, installs nuitka into it, and uses that Python for all subsequent steps. The .tool_env/ is reused on every future run.
The node's own dependencies (torch, numpy, Pillow, etc.) are also installed automatically — into an isolated build folder, never into your system or any shared environment.
Platform extras (these can't be auto-installed):
- Linux:
apt install patchelf - macOS:
brew install ccache(optional, speeds up rebuilds) - Windows: Visual Studio Build Tools (required by Nuitka)
# Pack any custom node directory
python pack.py <path/to/your_node>
# Examples
python pack.py my_node # example node bundled in this repo
python pack.py ~/ComfyUI/custom_nodes/my_cool_node # any node on disk
# Override the output package name (useful if the dir name is not a valid Python identifier)
python pack.py my_node --name my_cool_node_v2
# Choose a different output root
python pack.py my_node --output /tmp/dist
# Vendor deps but skip Nuitka (useful for testing the vendoring step alone)
python pack.py my_node --skip-compileThe packed folder lands in dist/<package_name>/. Copy it into ComfyUI:
cp -R dist/my_node /path/to/ComfyUI/custom_nodes/Your custom node directory must contain:
| File | Purpose |
|---|---|
requirements.txt |
pip packages to isolate |
nodes.py |
main module — compiled by Nuitka |
__init__.py |
ComfyUI registration (NODE_CLASS_MAPPINGS etc.) — copied as-is |
__init__.py typically just re-exports from .nodes and defines NODE_CLASS_MAPPINGS, so it works unchanged with the compiled extension.
If your main file isn't named nodes.py, the packer will use the only other .py file in the directory (if there is exactly one).
Just add the package to requirements.txt — no other configuration needed. The packer auto-discovers every package installed by pip, including transitive dependencies, and vendors all of them.
Previously, you would have had to maintain manual IMPORT_NAME_OVERRIDES and IMPORT_REWRITES dicts. Those are gone.
Keep these on the host — the packer skips them automatically:
torch numpy torchvision torchaudio comfyui folder_paths
ast.unparse()is used for import rewriting, which normalises whitespace and strips comments from the staged source. The compiled output is unaffected; comments appear only in the intermediate file fed to Nuitka.- The compiled extension is tied to your build machine's Python version, OS, and CPU architecture. Rebuild for each target runtime.
- Native wheels (e.g. Pillow) must be copied whole and validated against the target OS and Python version.
my_node/ is a minimal ComfyUI node bundled as a usage example. It exposes two nodes — Color Grade and Sharpness — that depend on Pillow, humanize, and python-slugify, all of which get vendored automatically.
