The most frustrating thing about web-based image generators isn't speed-it's that the next image never matches the last. You finally tune a composition and look you love, change one prompt word, re-roll, and the character's face shifted, the style drifted, and you can't reproduce it. Midjourney's --seed offers a partial lock, but the moment you need fine control over a character's features, a fixed artist's brushstroke, or one protagonist across a series of images, web UIs are essentially out of answers. This is why serious users skip the web and go straight to ComfyUI-it breaks generation into connectable nodes, puts every parameter in your hands, and with a fixed seed plus a reference image delivers "same params, same result."
This is the hands-on SOP that pairs with our ComfyUI resource piece (why pros don't use the web UI). It walks the full flow from install to reproducing a consistent style: install ComfyUI, place models right, build a base txt2img workflow, lock results with a fixed seed, then push further with LoRA and IPAdapter to nail down style and character. Each step ships real commands and copy-paste params, with a pitfalls section and FAQ at the end.
1. Why Consistency Is Hard: Positioning and Approach
Nail the problem first so you pick the right technique. "Inconsistency" in image gen has three layers, each with a different fix:
- Non-reproducible results: the same prompt run twice yields two completely different images. Root cause is randomized starting noise; the fix is a fixed seed. This is the baseline-every workflow must do it.
- Style drift: changing the prompt's subject drags the style with it, e.g. sliding from photoreal to cartoon. The fix is a LoRA (lock a style) or IPAdapter (transfer style from a reference image).
- Character not fixed: the same character looks different-hair, outfit, features-across images. This is the hardest layer; the fix is a character-specific LoRA, or IPAdapter FaceID to "stamp" one reference face onto every image.
This SOP escalates by difficulty: first nail "fixed seed reproducibility," then add LoRA to lock style, finally bring in IPAdapter for reference-image guidance. Stack all three and you get "one character, one style, stable across images."
2. Install: Three Ways to Get ComfyUI
Prerequisites: an NVIDIA GPU (AMD works but the ecosystem trails a notch), Python 3.10+, and Git. ComfyUI offers three official install paths-pick by your comfort level:
# Option 1: comfy-cli (official CLI, cross-platform, for those with Python basics)
pip install comfy-cli
comfy install # installs ComfyUI core, deps, and a virtualenv
comfy launch # starts it, default at http://127.0.0.1:8188
# Option 2: Windows Portable (bundles Python 3.11, zero env setup, for beginners)
# Download ComfyUI_portable_windows from docs.comfy.org, extract, double-click
# run_nvidia_gpu.bat to launch
# Option 3: ComfyUI Desktop (official desktop client, with a model manager UI)
# Grab the installer from the official site, one-click install, no terminal neededAfter launch, open http://127.0.0.1:8188 in a browser-when you see the node canvas, it's running. Your first job is to install ComfyUI Manager, the gateway for installing custom nodes (IPAdapter etc.). Method: drop into ComfyUI/custom_nodes, git clone the Manager repo, restart ComfyUI; a "Manager" button appears in the side menu, and inside it "Install Custom Nodes" lets you search and install any community node.
Pitfall: keep your portable extract path free of non-ASCII characters and spaces, or model loads can intermittently error; don't install comfy-cli and the portable build into the same directory-their configs will clash.
3. Load: Place Models Right and Pick a Base Checkpoint
ComfyUI won't hunt for models-you manually drop checkpoints into the right folders:
ComfyUI/
├── models/
│ ├── checkpoints/ # base models go here (.safetensors)
│ ├── loras/ # LoRAs go here
│ ├── ipadapter/ # IPAdapter models go here
│ └── vae/ # VAE (some models ship one built in, skip)
└── custom_nodes/ # custom nodes (e.g. ComfyUI_IPAdapter_plus)Checkpoint choice caps your style ceiling. Two mainstream options today:
- SDXL: native 1024x1024, the most mature ecosystem with the most LoRAs and IPAdapter models, runnable on 8GB VRAM. The recommended starting point for a consistent-style workflow. Go with
sd_xl_base_1.0or a community fine-tune. - Flux: beats SDXL on image quality and prompt adherence, but VRAM-hungry (12GB minimum, the 1.0 optimized version compresses to 8GB), and its LoRA / IPAdapter ecosystem trails SDXL. Best for image-quality-first users willing to tinker.
Recommendation: build your first consistent-style workflow on SDXL to get the whole chain working, then migrate to Flux. Don't start on Flux-the fewer models and tighter VRAM double your tuning variables.
4. Build: Base txt2img Workflow + Fixed Seed
This step builds the smallest reproducible workflow. ComfyUI ships a default txt2img template on the canvas-build on it. Node wiring order:
- CheckpointLoaderSimple (load checkpoint) -> outputs MODEL, CLIP, VAE
- CLIPTextEncode x2 (positive / negative prompt) -> fed CLIP
- EmptyLatentImage (set dimensions, e.g. 1024x1024) -> outputs empty latent
- KSampler (core sampling) <- takes MODEL, positive, negative, latent
- VAEDecode <- takes KSampler's latent + VAE -> outputs image
- SaveImage <- takes image
The crux is the KSampler's six params-the core knobs of reproducibility:
| Parameter | Recommended | Purpose |
|---|---|---|
| seed | fix a number (e.g. 42) | sampling start; fixed = reproducible |
| steps | 20-30 | more = finer but slower; 25 is the balance |
| cfg | 5-8 | prompt adherence; too high burns out, too low drifts |
| sampler_name | dpmpp_2m | sampler; dpmpp_2m is stable; euler is fast; euler_ancestral adds detail but is more random |
| scheduler | karras | noise decay schedule; karras + dpmpp_2m is the consensus-stable combo |
| denoise | 1.0 | 1.0 for txt2img; 0.3-0.7 for img2img edits |
One line to remember: to reproduce, the seed must be fixed. By default KSampler's seed is randomized (click "randomize"). Once you get an image you like, note its seed, switch the control from "randomize" to "fixed," enter that seed, and re-run-you'll get essentially the same image. This is the foundation of all consistency work.
Below is this base workflow's API JSON snippet (save as .json, then drag-drop via ComfyUI's "Load"; node IDs match the default template):
{
"3": {
"class_type": "KSampler",
"inputs": {
"seed": 42,
"steps": 25,
"cfg": 7,
"sampler_name": "dpmpp_2m",
"scheduler": "karras",
"denoise": 1.0,
"model": ["4", 0],
"positive": ["6", 0],
"negative": ["7", 0],
"latent_image": ["5", 0]
}
},
"4": { "class_type": "CheckpointLoaderSimple", "inputs": { "ckpt_name": "sd_xl_base_1.0.safetensors" } },
"5": { "class_type": "EmptyLatentImage", "inputs": { "width": 1024, "height": 1024, "batch_size": 1 } },
"6": { "class_type": "CLIPTextEncode", "inputs": { "clip": ["4", 1], "text": "a girl with red hair, cinematic photo, highly detailed" } },
"7": { "class_type": "CLIPTextEncode", "inputs": { "clip": ["4", 1], "text": "blurry, lowres, deformed" } },
"8": { "class_type": "VAEDecode", "inputs": { "samples": ["3", 0], "vae": ["4", 2] } },
"9": { "class_type": "SaveImage", "inputs": { "images": ["8", 0], "filename_prefix": "consistent_style" } }
}Get this working and you can reproduce a single image. But change the prompt (red hair to blonde) and the style may still drift. Next section fixes that.
5. Lock: Fix Style or Character with a LoRA
A LoRA (Low-Rank Adaptation) is a lightweight fine-tune layered onto the base model-tens to hundreds of MB-that "welds" a specific style or character onto the model. With the right LoRA, you can swap prompts and compositions and the style stays bolted in place.
Install a LoRA: drop the .safetensors into models/loras/ and refresh ComfyUI. Add a Load LoRA node on the canvas, inserted between CheckpointLoaderSimple and KSampler:
CheckpointLoaderSimple -> Load LoRA -> KSamplerKey Load LoRA params:
- lora_name: pick your LoRA file
- strength_model / strength_clip: intensity; 1.0 is stock, 0.8 weaker, 1.2 stronger. Usually 0.7-1.0-too high produces artifacts and image collapse
To lock a style, grab a style LoRA (oil painting, cyberpunk, ink-wash); to lock a character, grab a character-specific LoRA (CivitAI hosts a vast catalog). Also add the LoRA's trigger word in the prompt (the download page lists it, e.g. chara_aria) for a steadier effect.
Pitfall: LoRAs must match the base model version-SDXL LoRAs pair only with SDXL bases, SD1.5 LoRAs only with 1.5. Mixing them either errors or produces garbage. Check the stated base version before downloading.
6. Transfer: Guide Style with a Reference Image via IPAdapter
LoRAs solve "I want this style," but sometimes you only have a reference image and no ready-made LoRA, and want the model to "paint in that image's style or with that character." Enter IPAdapter. It extracts the reference image's features and injects them into the generation, steering the model toward the reference's style or character-without any training.
Install IPAdapter:
- Via ComfyUI Manager, search
ComfyUI_IPAdapter_plus(author cubiq), click Install, then restart ComfyUI. - Download an IPAdapter model (e.g.
ip-adapter-plus_sdxl_vit-h.safetensors) and drop it intomodels/ipadapter/.
Note: IPAdapter models must match the base version-an SDXL base pairs only with the SDXL IPAdapter, SD1.5 with the 1.5 version. Mismatched versions error out or yield zero effect.
Build the workflow: add a Load Image (load the reference) and an Apply IPAdapter node to the step-4 base flow:
Load Image -> Apply IPAdapter -> KSampler (MODEL input)Apply IPAdapter's core param weight controls the reference's influence; 0.5-0.8 is a safe starting range-too high and the output becomes a copy-paste of the reference, too low and it does nothing.
Advanced: to lock a character's face, use IPAdapter FaceID (purpose-built to extract facial features)-far stronger character consistency than the general IPAdapter. Combined with a fixed seed, one character stays highly consistent across different scenes. This is exactly what web UIs can't do.
7. Pitfalls from the Trenches
Pitfall 1: Not fixing the seed and calling it "stable style." Many beginners get an image they like, change the prompt, re-roll, and watch everything change-assuming the model is bad. The real issue: the seed was in randomize mode, so it changes every run. Step one is always: like an image, note the seed, switch to fixed, re-run to verify.
Pitfall 2: LoRA / base model version mismatch. An SDXL LoRA on an SD1.5 base either throws a dimension error or produces garbage. Check the stated base version on CivitAI / the download page before grabbing-don't judge by the thumbnail alone.
Pitfall 3: IPAdapter model in the wrong folder or wrong version. It must go in models/ipadapter/ (not models/loras/), and an SDXL base pairs only with the SDXL IPAdapter. If it has no effect after install, nine times out of ten it's the path or the version.
Pitfall 4: Out of Memory (VRAM blowout). SDXL on 8GB at 1024x1024 is near the limit; adding LoRA and IPAdapter tips it over. Fix: launch with the --lowvram flag before the VAEDecode latent, or drop the resolution to 768x768 and upscale-don't brute-force high resolutions.
Pitfall 5: Not restarting after installing a custom node. After ComfyUI Manager installs IPAdapter and the like, you must restart ComfyUI to load the new nodes. Without a restart you go hunting for Apply IPAdapter, find it missing, assume the install failed, and reinstall-when all you needed was a restart.
Pitfall 6: Random sampler + scheduler combos. Not every sampler pairs with karras. dpmpp_2m + karras is the recognized stable combo; euler_ancestral + normal is also common. Wild combos (e.g. ancestral + karras) can produce noisy output. When unsure, default to dpmpp_2m + karras.
8. FAQ
Q1: What's the minimum VRAM to run ComfyUI? SDXL starts at 8GB (1024x1024, 25 steps), but once you add LoRA and IPAdapter, aim for 12GB+. Flux's 1.0 optimized version runs on 8GB; the full version needs 16GB+. If VRAM is short, use the low-VRAM launch flag or lower the resolution-don't brute-force it.
Q2: Can I use ComfyUI if I can't code? Yes. ComfyUI is visual drag-and-drop node wiring, no code. The barrier is understanding node relationships, not programming. Start with the Windows portable build for zero-env setup, then modify the default txt2img template-follow this SOP once and you're in.
Q3: How do I lock one character's face so it stays consistent across images? The most reliable path is a character-specific LoRA (CivitAI has plenty ready to use), paired with a fixed seed and the trigger word. Without a LoRA, use IPAdapter FaceID: feed one reference face of the character, and that face's features get injected into every image. Stack both for the best result.
Q4: My output is blurry-what do I do? Three checks: one, steps too low (under 15 is soft, go 20-25); two, cfg too low (under 4 blurs and diffuses); three, resolution-512x512 is always blurry on SDXL, which is natively 1024x1024 (at least 768). A mis-wired VAE also blurs-confirm VAEDecode uses the base model's built-in VAE.
Q5: Can I commercially use images from ComfyUI? It depends on the license of your base model and LoRAs. The SDXL base model (sd_xl_base from Stability AI) permits commercial use, but community LoRAs vary-CivitAI labels each as "Commercial" or "Non-Commercial," so read before downloading. Flux's dev version is non-commercial; the pro version is commercial. For any commercial use, verify every model's license-don't assume.
References
- ComfyUI Docs - comfy-cli Getting Started
- ComfyUI Docs - KSampler Node
- ComfyUI Docs - Windows Portable Install
- ComfyUI-Manager Install Docs
- ComfyUI_IPAdapter_plus (cubiq) GitHub Repository
- Getting Started with ComfyUI IPAdapter Plus - Weird Wonderful AI Art
- ComfyUI KSampler Explained - ComfyUI Community Manual