Nodes/ComfyUi-MpiNodes/Mpi FLUX 3 References
ComfyUI Node

Mpi FLUX 3 References

Ten Reference Slots Without the Autogrow Dance

By MadPonyInteractive·Created about a year ago·Updated 4 days ago· 3
Mpi FLUX 3 References
  • clip
  • vae
  • negative
  • ref_image_0
  • ref_image_1
  • ref_image_2
  • ref_image_3
  • ref_image_4
  • ref_image_5
  • ref_image_6
  • ref_image_7
  • ref_image_8
  • ref_image_9
  • positive
  • negative
  • empty_latent
  • ref_tags
◄prompt—►
◄resolutionresize►
◄megapixels1.00►

What this node is actually for

Reference conditioning, the modern way. Since Kontext taught people you can hand an image model a picture and a sentence instead of a LoRA, "put this face / this jacket / this font into the shot" became the default way to get consistency without training anything. Flux 2 pushed that to up to ten references in one context, and FLUX 3 Image Klein is where the line is now - so citing several references at once is normal, not exotic.

Which is exactly where ComfyUI's stock reference node gets awkward. Core's Set Reference Multi Latent grows its image inputs one at a time, an Autogrow slot per reference. Fine when you're hand-wiring at 2 a.m. Not fine for anything authored ahead of time: a saved workflow or a host app has no way to add a slot at inject time, and an empty slot wired from a loader that emits its "nothing here" stand-in gets encoded as a real reference. MpiFlux3References takes the boring route - all ten slots present all the time, and the empty ones thrown away.

Why ten flat slots is the whole trick

ref_image_0 through ref_image_9 are plain optional inputs, always there. Leave one unconnected and it's skipped. Connect a loader sitting on an empty path and it's also skipped - this pack's loaders emit a 1×1 image when block_if_empty is off, and the node treats a 1×1 as "nothing". A genuinely black reference reports its real size and goes through; it isn't guessing from content.

Then it renumbers the survivors and hands them to core's own ReferenceMultiLatent, so the tensor maths is ComfyUI's and not a private copy that rots when core changes. One graph covers every combination of one to ten references.

Write the prompt against slot numbers

This is the bit people trip over, and it's the point. You cite references by the slot you wired them into - <ref_image_0>, <ref_image_3> - not by the order the model ends up seeing them. The node knows both numberings, so it rewrites your tags to match what core presents and drops any tag pointing at an empty slot.

So with slots 2 and 5 wired and the rest empty:

Put the hat from <ref_image_5> on the man in <ref_image_2>, ignore <ref_image_0>.

becomes <ref_image_1> and <ref_image_0>, and the dead tag is deleted (the words around it stay - you get "ignore .", the least-bad option). Bare ref_image_N values in a layout table's "from" field move with the same renumbering; a bare empty one is left alone, because yanking it would break the JSON. The ref_tags output is the map it produced, as a string - wire it to a text display node the first few times.

The inputs you set, and the outputs

Required: clip and vae (the model's own text encoder and VAE - this node encodes the prompt and the references itself), prompt (multiline, and yes it accepts dynamic prompts), resolution (resize or keep resolution), and megapixels (target size per reference when resizing - 1.0 is roughly 1024×1024, aspect kept).

Leave resolution on resize and the references around 1 MP each. Ten full-resolution camera files is a lot of latent tokens for no gain, and it's the commonest way to turn a working graph into a VRAM apology.

Optional negative picks up the same reference latents. Wire nothing and the negative output just repeats the positive, same as core - which is why a negative prompt feels like it does nothing on reference runs.

Outputs: positive, negative, empty_latent, ref_tags. Wire the first two into your sampler. Watch the latent. empty_latent is core's - with references it's the first reference's latent times zero, and with no references it's a square 4-channel SD latent, which is wrong for FLUX 3. For a text-to-image pass, take your latent from core's EmptyFlux2LatentImage and let empty_latent be.

Install

The pack ships no requirements file and downloads no models - it runs on the torch/Pillow/scipy ComfyUI already installs. Easiest route is ComfyUI Manager: search ComfyUi-MpiNodes (publisher mad-pony-interactive, Comfy Registry). Manually:

cd ComfyUI/custom_nodes
git clone https://github.com/MadPonyInteractive/ComfyUi-MpiNodes
# then restart ComfyUI

You need the FLUX 3 weights plus their separate CLIP and VAE files, loaded by your usual loaders. Nothing is bundled.

Where it goes wrong

"ReferenceMultiLatent is missing - MpiFlux3References needs ComfyUI 0.41.0 or newer." The node refusing cleanly rather than half-working. Update ComfyUI; the core class it delegates to is the whole conditioning path.

The model ignores a reference you clearly wired. Check ref_tags. Either the slot was empty by the node's definition - a 1×1 sentinel from a loader sitting on a path that didn't load - or you cited a slot whose tag then got dropped. Reading the map takes ten seconds.

Everything is slow and you're near OOM. Ten references is ten encodes. Cut megapixels before you cut references - 0.5 MP still carries identity, and one graph handling "sometimes two references, sometimes seven" is the whole point of the node.

CategoryMpiNodes/Utils

Inputs (16)

NameTypeDefaultDescription
clipCLIP—
vaeVAE—
promptSTRINGCite references by SLOT: <ref_image_0> is whatever is wired into ref_image_0. The node rewrites tags to the order core presents once empty slots are dropped (see ref_tags); a tag naming an empty slot is removed.
resolutionCOMBOresizeresize scales each reference to `megapixels`, aspect kept. keep resolution encodes it as it is.
megapixelsFLOAT1.000.01–16Target size of each reference when resolution is resize. 1.0 is about 1024 x 1024.
negativeoptCONDITIONINGOptional. Gets the same reference latents. Unconnected, the positive is returned in its place, as core does.
ref_image_0optIMAGEReference image, cited in the prompt as <ref_image_0>. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_1optIMAGEReference image, cited in the prompt as <ref_image_1>. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_2optIMAGEReference image, cited in the prompt as <ref_image_2>. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_3optIMAGEReference image, cited in the prompt as <ref_image_3>. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_4optIMAGEReference image, cited in the prompt as <ref_image_4>. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_5optIMAGEReference image, cited in the prompt as <ref_image_5>. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_6optIMAGEReference image, cited in the prompt as <ref_image_6>. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_7optIMAGEReference image, cited in the prompt as <ref_image_7>. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_8optIMAGEReference image, cited in the prompt as <ref_image_8>. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.
ref_image_9optIMAGEReference image, cited in the prompt as <ref_image_9>. Leave unconnected, or feed a loader with block_if_empty OFF, to skip it.

Outputs (4)

NameTypeDescription
positiveCONDITIONING—
negativeCONDITIONING—
empty_latentLATENT—
ref_tagsSTRING—