π Path Join
Stop hardcoding C:\\Users\\you\\ in your workflows
- Path
There is a specific kind of ComfyUI pain that comes from a workflow somebody shared with path_override set to D:\AI\output\stuff. It works for them. It does not work for you. Path Join is the unglamorous node that fixes this class of problem: build the path out of pieces, with the right separators for whatever OS is running, and let the graph own the structure.
How it works
It strips whitespace from each segment, converts backslashes to forward slashes, drops empty segments, then calls os.path.join on what's left and runs the result through os.path.normpath. That normalisation is what collapses doubled separators, resolves . and .., and converts the whole thing to the host platform's separator - backslashes on Windows, forward slashes everywhere else.
The consequence of using real os.path.join semantics is that an absolute segment resets everything before it. Join C:/models with D:/output and you get D:/output; the earlier segment is discarded. It's the same rule that bites people in Python, and it's actually useful once you know it: you can put a "base directory" in Segment 1 and then override it per-workflow by making Segment 2 absolute. Just don't be surprised when a segment that starts with a drive letter or a leading slash eats the join.
Segments are unified to forward slashes before joining, which is what makes mixed-separator input safe: C:\Users\me + output/portraits doesn't produce the C:\Users\me\output/portraits mess you'd get from naive concatenation.
The inputs and outputs that matter
Segment 1 is required and is the only one with a tooltip - "first path segment (e.g. a base directory)". Segments 2 through 5 are optional STRING inputs, default empty. Empty ones are simply skipped, so a four-deep path and a two-deep path use the same node; you just leave the tail blank.
One output: Path. Wire it into anything that takes an absolute path - Save Image's path_override (a directory), Load Image's path_override (a file), Move File's destination_path, Rename File, List Files' directory. It's the connective tissue of the entire File System group and honestly most of the reason the group is usable at all.
The pairing you'll build once and reuse: Text Concatenate to build a filename out of a model name and a sampler (its separator and whitespace-replacement defaults are tuned for exactly this), then Path Join to attach that filename to an output directory, then Save Image with path_override on the directory and filename on the base name. Every part of it becomes data, none of it is hardcoded, and the same workflow runs on someone else's machine.
Because these are ordinary STRING widgets, any of them can be converted to an input and driven by upstream values - that's how you get per-model subfolders without editing the node between runs.
How to install it
In Avaray/honda-nodes - ComfyUI Manager β Node Pack β search Honda Nodes β Install β restart. Or:
cd ComfyUI/custom_nodes
git clone --depth 1 https://github.com/Avaray/honda-nodes.git
cd honda-nodes
python install.py
No dependency on install.py for this node (stdlib only), but run it once anyway - the pack's JSON and metadata nodes need the jq and ime binaries it downloads. No pip packages, no models.
Common issues
The first segment vanished. You made a later segment absolute. os.path.join reset the result - that's documented behaviour, and the node's own description calls it out.
The path looks right in the widget but the destination node can't find it. Path Join normalises; it does not verify. A folder that doesn't exist yet is still a perfectly valid output string - and some consumers (Move File) create parents for you while others (Read File) will just fail. Check with List Files or paste it into a Text Preview before assuming the path is the problem.
It has backslashes in the widget but the node you're feeding wants forward slashes. You're on Windows: normpath converts to native separators, which is what all the pack's file nodes expect. If you're feeding it to something that wants a URL or a /view-style relative path, you're using the wrong node - that's a different problem.
The workflow someone shared still had a hardcoded drive letter in it. Not this node's fault, but this is the node that removes it. If a segment is a literal string widget, leave it blank-by-default in the workflow you share and put your real paths in the segments that are wired from a Text node.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| segment_1 | STRING | First path segment (e.g. a base directory). | |
| segment_2opt | STRING | β | |
| segment_3opt | STRING | β | |
| segment_4opt | STRING | β | |
| segment_5opt | STRING | β |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| Path | STRING | β |