Nodes/NF Suite/NF Prompt Template
ComfyUI Node

NF Prompt Template

NF Prompt Template

By NyaFuP·Created 24 days ago·Updated 7 days ago· 1
NF Prompt Template
    • positive
    • negative
    ◄template_id►
    ◄variables{}►
    ◄snapshot►
    ◄pin_snapshotfalse►
    ◄input1—►
    ◄input2—►

    Most prompt advice boils down to a structure you already know is right and then fail to follow, because the text box is empty and typing the whole thing again is annoying. Camera, subject, wardrobe, location, light - five slots, and every generation you retype them from scratch, drifting a little each time.

    NF Prompt Template turns that into a form. You save the skeleton once, with placeholders like {quality}, {character}, {location}, {lighting}, and the node grows one input field per placeholder. Fill the fields, and it emits the assembled prompt on positive plus the template's own negative prompt on negative. Two outputs, because a good template carries both.

    Why it's worth the setup

    The payoff isn't convenience, it's consistency. Photorealism prompting has converged hard on naming physical gear - cameras, film stocks - rather than mood words, and that vocabulary is specific enough that you don't want to retype it. "Shot on Kodak Portra 400" typed once into a template variable is worth more than the same words retyped with a typo eleven times. And on tag-based models, where block order matters, hand-rewriting the prompt is how block order quietly changes.

    The other half is speed: templates live in a library, you pick one from a dropdown, and its placeholder fields appear on the node. Empty fields count as empty strings, so a template can be a finished default prompt you twist one variable on, or a bare skeleton you fill from nothing.

    How it works

    The library is a JSON file on disk - ComfyUI/user/__nf_prompt_template/templates.json by default, or wherever you point the NF_PROMPT_TEMPLATE_DIR environment variable. It's a versioned document with a templates array; each entry has an id, a name, a template string, an optional negative_prompt, and a variables map of placeholder defaults. You never have to touch the file (there's a pencil button on the node and a "Prompt Templates" tab in the sidebar), but it is plain JSON, so you can version it in git or check in a house style.

    Expansion itself is deliberately conservative. Only {identifier} gets replaced - a name starting with a letter or underscore, followed by letters, digits or underscores. {{braces}} and {a|b} alternatives are left untouched, which is the smart bit: that's Dynamic Prompts wildcard syntax, so this node composes with a batching wildcard node instead of eating its syntax. Any placeholder without a value is left in the text and reported as a warning, never an error. After substitution, the fragments left behind by empty variables get cleaned up - runs of commas and periods collapse, doubled spaces go, an empty line is dropped, and a trailing comma that exists only because a variable was empty is removed (a comma the template itself ends with is kept, because you probably meant it). Unbalanced brackets are warnings too.

    The subtle part is reproducibility. On every queue, the node stores the content of the template it used as a snapshot inside the widget. If the template was later renamed, edited or deleted from the library, the workflow still runs - from the snapshot. The resolution order is: pin_snapshot on means snapshot or error; template found in the library means use the library, and warn if the snapshot differs from it; template missing means fall back to the snapshot; nothing usable means error.

    The inputs and outputs

    • template_id - which template to use. Normally set by the dropdown UI rather than typed.
    • variables - a JSON object of your values, filled in by the per-variable fields on the node. Anything missing falls back to the template's default.
    • snapshot - the captured template content, filled automatically at queue time.
    • pin_snapshot - BOOLEAN, default off. Turn it on to always use the snapshot even if the library changed, i.e. to freeze this node's output against future editing.
    • text (optional) - a STRING input for a text source from elsewhere in the graph. When connected, its content replaces {input} in the template, and the input field is greyed out. This is the LLM hook: template handles the structure, the model writes the creative part.

    Outputs: positive and negative, both STRING - wire them into your CLIP Text Encode nodes.

    One thing under the hood: the node's cache key is a hash of the resolved template content plus your variables, so editing a template in the sidebar correctly invalidates the nodes using it. You don't have to clear anything manually.

    Installing it

    The template editor is a frontend feature, and the frontend ships prebuilt, so there's nothing to build:

    cd ComfyUI/custom_nodes
    git clone https://github.com/NyaFuP/ComfyUI-NF_Suite.git
    

    Restart. No pip packages (the project declares zero dependencies), no models. ComfyUI 0.22.0+ and frontend 1.44.19+ are required - this pack uses the V3 node API, and the node's custom UI is a Vue widget. Find it under NF Suite/prompt. A starter library ships with the pack and gets seeded into your library file on first use; the editor's duplicate button is how you turn one good template into a set.

    Common issues

    "Variable is not defined" warnings. You used a placeholder that isn't in the template's variable list, so it was left in the output verbatim. Warnings mean the run still happens; read them in the console rather than assuming the prompt was fine.

    variables errors. The widget has to be a JSON object whose values are all strings. A stray number, a list, or a missing quote produces a clear validation error rather than a half-expanded prompt.

    pin_snapshot with no snapshot. If you tick it on a node that has never been queued, there is no snapshot to pin and it errors. Untick, run once, then pin.

    Library file corrupted. If the JSON gets broken by a hand edit, the library is treated as unavailable rather than silently overwritten, and nodes fall back to their snapshots - so your workflow keeps working while you fix the file. That's also your migration story: send someone the workflow and they'll get a template_missing warning and use the snapshot, so their output matches yours even without your library.

    The connected text input does nothing. The template has no {input} placeholder, so there's nothing to substitute. The node warns about exactly this case.

    CategoryNF Suite/prompt

    Inputs (6)

    NameTypeDefaultDescription
    template_idSTRINGTemplate id in the library
    variablesSTRING{}JSON object of variable values. Missing keys use the template defaults.
    snapshotSTRINGTemplate content captured at queue time (JSON). Used when the template is missing or pinned.
    pin_snapshotBOOLEANfalseAlways use the snapshot instead of the library
    input1optSTRING—
    input2optSTRING—

    Outputs (2)

    NameTypeDescription
    positiveSTRING—
    negativeSTRING—