Modal Render (Symbiotica)
Qwen-Image on rented silicon, six widgets wide
- image
What this node is actually for
Qwen-Image is a 20B model - roughly 20GB for the fp8 diffusion weights plus ~8GB for the vision encoder, hence the community's "absolute VRAM hog." The Modal Render node is the escape hatch: it hands a pinned graph to a ComfyUI running on Modal and returns the image on an ordinary IMAGE socket. Nothing downloads, nothing touches your VRAM.
That's the third bucket from our API-nodes writeup: not "the model has no open weights," but an open model on somebody else's GPU. Same tradeoffs - your prompt leaves the machine, and you're queued behind a stranger.
One thing up front: the pack's Claude and Gemini nodes take a key you already own. Here you need a render endpoint URL plus a proxy token pair issued by a Symbiotica hub. Without those it's a tidy placeholder - a client for a deployed lane, not a Modal account in a box.
How it works
The graph is fixed server-side per recipe. The node copies that recipe's API-format JSON, writes prompt, negative, seed, width and height into the nodes its manifest names, drops the manifest block (ComfyUI rejects a node with no class_type), and POSTs it.
POST <endpoint>/submit {"workflow": <bound graph>} -> {"call_id": "..."}
GET <endpoint>/status ?call_id=... -> 202 running | 200 succeeded
Headers are Modal-Key and Modal-Secret. The node polls every two seconds, then turns image_b64 into a [1,H,W,3] float tensor and previews it. The render is capped at 540 seconds on Modal's side, but the node waits up to 30 minutes, because much of that clock is waiting for a GPU to free up. Cancel stops the polling, not the render - that finishes and bills either way.
The recipe list is just filenames: any *.api.json in the pack's py/modal_workflows/. It ships with one, qwen-image: Qwen-Image 2512 fp8 with the 4-step Lightning LoRA, cfg 1.0, euler/simple, AuraFlow shift 3.1 - about 70 seconds once it starts. Recipes ignore values they don't bind, so these six widgets can drive any future recipe.
The inputs that matter
- recipe - the only real decision, and right now it has one answer:
qwen-image. - prompt - this does all the work. Lightning at 4 steps is fast, not forgiving, so be specific rather than poetic.
- negative - the author's tooltip says it flat: Lightning runs at cfg 1, so this "carries little weight."
- seed - 0 to 2^64−1, with
control_after_generateattached. It fires after the run like every seed widget, so set it to fixed when you get something good, or flip widget control mode to "before" in Settings. - width / height - 1024 default, 256–2048, snapped to 16.
Output is a single image (IMAGE). The node is not an output node, so nothing lands on your disk until you wire it into Save Image or an upscaler.
There's no IMAGE input: the render container mounts the models volume only, so this is text-to-image - no img2img, no ControlNet, no reference images yet.
Install
# ComfyUI Manager: search "Symbiotica" and install.
cd ComfyUI/custom_nodes
git clone https://github.com/symbiotica-ai/comfyui-nodes.git symbiotica
pip install -r symbiotica/requirements.txt
That requirements file is requests and pillow - no torch extras, no model downloads, because the models live on the Modal side. The credential triple goes in Settings → Symbiotica → Modal: Render endpoint URL (https://symbiotica-<env>--symbiotica-comfy-api.modal.run), Proxy token id (wk-…), Proxy token secret (ws-…). Env equivalents are MODAL_ENDPOINT_URL, MODAL_TOKEN_ID, MODAL_TOKEN_SECRET, and Settings wins on purpose - on Comfy Desktop, Electron hands Python nothing. The same panel holds RNP_SERVER_URL, which fetches a node per recipe at startup.
Where people get stuck
"MODAL_ENDPOINT_URL is not set." All three values go together - endpoint plus both halves of the token pair. The error names the missing one.
401, token refused. You pasted a Modal CLI token. It has to be the proxy pair (wk-… / ws-…) from the hub's proxy-token secret.
A non-https endpoint is refused by name, not quietly downgraded - the token rides in every call's headers.
The 30-minute give-up is usually a queue, not a crash. The error points at modal app logs -e dev symbiotica-comfy -f and the phrase waiting to be scheduled. Or poll it yourself:
curl -s "$MODAL_ENDPOINT_URL/status?call_id=$CALL_ID" \
-H "Modal-Key: $MODAL_TOKEN_ID" -H "Modal-Secret: $MODAL_TOKEN_SECRET"
A 202 means still in flight; a 200 reporting failed carries the endpoint's own error, which the node surfaces.
The node isn't in the menu. Each module imports defensively, so a failure prints [Symbiotica] Failed to load modal_render with a traceback rather than taking the pack down. This node uses ComfyUI's V3 comfy_api.latest schema, so an old build is the first suspect.
recipe is empty. The combo is a directory listing - empty means py/modal_workflows/ is bare or SYMBIOTICA_MODAL_RECIPES points elsewhere. The pack README never mentions this node, so its description and the Settings tooltips are your documentation.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| recipe | COMBO | Which pinned graph runs on Modal. | |
| prompt | STRING | What to draw. | |
| negative | STRING | What to keep out, where the recipe has a negative prompt. | |
| seed | INT | 00–18446744073709550000 | — |
| width | INT | 1024256–2048 | — |
| height | INT | 1024256–2048 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |