🔷 Control Order & Free Memory
Run your nodes in the order YOU want — and take your VRAM back
- persist_any_1
- persist_any_1
ComfyUI decides what runs when - not you. It walks the graph, works out what data depends on what, and executes in dependency order. That's usually exactly right, and it's also exactly the problem when you've got multiple models fighting for the same VRAM: a big text encoder sitting allocated while you decode, or the Wan 2.2 High and Low KSamplers both trying to hold the 14B diffusion model. 🔷 Control Order & Free Memory is a router that forces an execution order you specify, and - optionally - unloads every model that isn't actively passing through it. It's the closest thing to "unload the text encoder now, dammit" that ComfyUI has.
How it works
The trick is simple and old: in a dataflow graph, if you route data through a node, everything feeding that node must finish before it runs, and everything it feeds runs after. This node is nothing but an AnyType (*) passthrough - it takes any number of inputs, hands each to its matching output unchanged, and by doing so creates an explicit, deterministic sequence in a workflow that otherwise has no "this must run before that" beyond data dependencies. Wire all the nodes that should run first into persist_any_N inputs, chain the ones that should run later off the matching outputs, and repeat as many times as you need.
The free_memory toggle (a BOOLEAN, default off) is where it earns its keep. When on, it unloads everything ComfyUI has loaded except any models routed through the node - using ComfyUI's own model_management internals (free_memory(1e30, …) or unload_all_models(), then soft_empty_cache, a gc.collect(), a double device cache clear, cleanup_models). It's device-agnostic, covering CUDA, MPS, XPU, NPU and MLU, and it prints a tidy report to the terminal of how much VRAM and RAM it actually freed.
Two implementation details matter for real life. First, the node hijacks LiteGraph's connection-change handler so its I/O slots grow automatically - connect the last persist_any slot and a new one appears, forever, as many as you like. Second, the "MatryoshkaTuple" return trick (borrowed from Trung0246's ComfyUI-0246) lets the output count grow without breaking ComfyUI's type validation. The only other trick worth knowing: this node is marked as an output node, so it works fine as the last thing in a chain with nothing connected after it.
The inputs that matter
You only really set one thing:
free_memory(BOOLEAN, defaultfalse) - unload all models not passing through, and clear VRAM/RAM. This is the whole memory-cleanup operation.
Everything else is persist_any_N - any type, any count. Latents, conditioning, images, masks, models, whatever. Each input passes to the same-numbered output untouched, and anything that's a model and still loaded survives the cleanup. That output wire is the "this data is now safe, proceed" signal.
Installing it
Zero dependencies - there's no requirements.txt, no model files, nothing but the two nodes and some JavaScript. ComfyUI Manager can find it by searching "Control Order & Free Memory", or just:
cd ComfyUI/custom_nodes
git clone https://github.com/mkim87404/ComfyUI-ControlOrder-FreeMemory.git
Restart ComfyUI, then double-click the canvas and search "Control Order & Free Memory". The repo ships example Wan 2.2 and LTX 2.3 workflows you can drag straight in.
Where people get burned
The big one is CLIP. ComfyUI unloads the CLIP/text encoder immediately after your conditioning nodes finish, so by the time it reaches this node it's a husk. Routing that dead object onward can produce malformed conditioning or OOMs downstream. Don't route CLIP itself - generate your conditioning right after loading it and pass the conditioning through instead. Some GGUF/quantized loaders have their own unloading logic and may drop themselves the same way; if a routed model misbehaves, use it immediately after loading and reload it in a later chain.
Two more things to set expectations. System RAM barely drops - that's ComfyUI deliberately caching node outputs for reuse, and no node can force that out mid-run. And if your GPU already fits everything at once, the unload/reload churn can make things slower, so test with the toggle on and off; the README notes Wan 2.2 tends to benefit more than LTX 2.3. One honest caveat from the author: the node leans on ComfyUI internals and JS prototype hooks, so a future ComfyUI update could break parts of it. If you want it to run a cleanup at the very start of every queue, wire an Int primitive in with a value that changes each run - ComfyUI skips nodes whose inputs didn't change, so a constant input means it never fires.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| free_memory | BOOLEAN | false | Unload all models and release as much VRAM & RAM as possible while routing & preserving all 'persist_any' passthrough data. Any models passed into 'persist_any' will stay loaded if they were not already unloaded by the sender nodes (e.g. CLIP / some GGUF loaders). If any routed model fails to persist, fallback to using it immediately after load and reload only when needed. Prints how much VRAM & RAM has been freed on the ComfyUI session terminal. |
| persist_any_1opt | * | Persist any type of data through to the next node e.g. latents, conditioning, images, masks, models (except CLIP / some GGUF models already unloaded by the sender nodes), etc. This data survives the 'free_memory' operation. I/O slots expand adaptively |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| persist_any_1 | * | Persist any type of data through to the next node e.g. latents, conditioning, images, masks, models (except CLIP / some GGUF models already unloaded by the sender nodes), etc. This data survives the 'free_memory' operation. I/O slots expand adaptively |