Nodes/String Join Tools/Optional String Join (10)
ComfyUI Node

Optional String Join (10)

Ten optional strings, one clean prompt — no empty slots

By ruminar·Created 2 months ago·Updated 27 days ago· 2
Optional String Join (10)
    • text
    separator,
    text_1
    text_2
    text_3
    text_4
    text_5
    text_6
    text_7
    text_8
    text_9
    text_10

    Optional String Join (10) is the biggest node in ruminar's String Join Tools pack, and it exists for one reason: real prompt assembly graphs have a lot of optional strings, and most of them come up empty some of the time.

    Here's the shape of the problem. You've got ten different upstream sources - wildcard pickers, LoRA trigger nodes, per-epoch settings, a hardcoded quality block, a subject, a scene, lighting, camera language. Any of them can be unconnected, bypassed, or produce an empty string on a given run. A naive concatenate node would turn that into a prompt full of ", , ," garbage. This node turns it into a single clean string with the separator only between the pieces that actually showed up.

    The behavior that makes it work

    Every one of the ten text sockets is optional and wire-only. Unconnected inputs are ignored. Inputs that arrive as an exact empty string are ignored. Inputs that go missing because an upstream node was bypassed are also accepted - this pack was written to treat a bypassed source the same as an unconnected socket, which is a genuinely nicer failure mode than most concatenators give you. Whitespace-only strings are kept (they're not empty), embedded line breaks survive, and the separator is inserted strictly between usable strings. If every input is missing or empty, you get "" back, which is the correct thing to feed a CLIP encoder.

    The separator field decodes a few escapes: \n for a line feed, \r\n for CRLF, \t for a tab, \\ for one backslash. Type \\n if you genuinely want the two characters \n. Unsupported sequences like \u or \x are passed through untouched.

    Wiring it in

    You only set two kinds of things:

    • separator - the one widget, default ", ". Set it once and mostly forget it.
    • text_1 through text_10 - optional STRING sockets. Feed each from whatever string source you have; leave the ones you don't need empty. Output is a single text STRING, which you run into your positive CLIP Text Encode (or a negative, or a saver's metadata, or another join).

    Because every input is optional, a 10-socket node doesn't force you to fill ten sockets. You can use three and ignore the rest - the unused ones simply never appear in the output.

    When ten isn't enough

    The README is explicit here: "For more inputs, connect join nodes in stages." Take the text output of this node into the text_1 slot of another join, keep feeding other sources into the remaining slots, and you can compose prompts from any number of branches. The node doesn't care; it just filters and joins.

    Installing it

    ComfyUI Manager: search "String Join Tools" or "ComfyUI-StringJoinTools" and install. Or manually:

    cd ComfyUI/custom_nodes
    git clone https://github.com/ruminar/ComfyUI-StringJoinTools
    

    Restart ComfyUI and refresh the browser. No extra Python packages, no model files to download - this whole pack is pure string plumbing, which makes it about the safest custom node install you can do. Find it under String Join Tools.

    The honest caveat

    For a beginner this node can feel like overkill - most prompts start as one text box. Where it genuinely earns its keep is the moment you stop typing prompts and start composing them from interchangeable parts, especially once a wildcard or random-choice node is in the mix. If you're not there yet, the 2/3/5 variants do the same job with less canvas. When you are, ten optional slots with empty-string forgiveness is exactly the tool you'll want.

    CategoryString Join Tools

    Inputs (11)

    NameTypeDefaultDescription
    separatorSTRING, Inserted only between usable strings. Supports \n, \r\n, \t, and \\.
    text_1optSTRINGOptional STRING input. Missing inputs and exact empty strings are ignored.
    text_2optSTRINGOptional STRING input. Missing inputs and exact empty strings are ignored.
    text_3optSTRINGOptional STRING input. Missing inputs and exact empty strings are ignored.
    text_4optSTRINGOptional STRING input. Missing inputs and exact empty strings are ignored.
    text_5optSTRINGOptional STRING input. Missing inputs and exact empty strings are ignored.
    text_6optSTRINGOptional STRING input. Missing inputs and exact empty strings are ignored.
    text_7optSTRINGOptional STRING input. Missing inputs and exact empty strings are ignored.
    text_8optSTRINGOptional STRING input. Missing inputs and exact empty strings are ignored.
    text_9optSTRINGOptional STRING input. Missing inputs and exact empty strings are ignored.
    text_10optSTRINGOptional STRING input. Missing inputs and exact empty strings are ignored.

    Outputs (1)

    NameTypeDescription
    textSTRING