Stop fighting the prompt for composition. ControlNet lets you show the model the pose, edges, or depth you want and have it follow that structure exactly while the prompt handles content and style.
Why Use ControlNet?
Prompts are great at describing what to generate but poor at controlling where things go. ControlNet closes that gap by conditioning generation on a structural reference. Understanding it unlocks several practical wins:
- Reliable composition - Reproduce a specific pose, layout, or perspective instead of rerolling seeds
- Sketch-to-image - Turn rough drawings or line art into finished renders
- Consistency - Hold a character’s pose or a scene’s geometry steady across many generations
-
Style-preserving structure - Restyle a photo while keeping its shapes and depth intact
- Control Maps. A preprocessor turns your reference into a pose skeleton, edge map, or depth gradient that steers every denoising step.
- Strength Is a Dial. Tune control influence (and when it applies) so structure guides the result without overriding the prompt.
- Composable. Combine with IP-Adapter for style and LoRAs for subjects — but stacking many ControlNets rarely helps.
What is ControlNet?
ControlNet is a neural network architecture that adds spatial control to diffusion models. It allows you to guide image generation using various types of conditioning inputs like human poses, edge maps, depth maps, and more, while maintaining the quality and capabilities of the base model.
As of 2024, ControlNet has evolved significantly with new control types, better preprocessing, and support for newer models. The ecosystem now includes alternatives like T2I-Adapter, IP-Adapter, and InstantID that offer different trade-offs between control precision and flexibility.
How ControlNet Works
flowchart LR
Ref["Input/reference image"] --> Pre["Preprocessor<br/>(pose, edge, depth…)"]
Pre --> Map["Control map"]
Prompt["Text prompt"] --> Base["Base diffusion model"]
Map --> CN["ControlNet<br/>(trainable encoder copy)"]
Base --> CN
CN --> Out["Controlled output"]
ControlNet creates a trainable copy of the diffusion model’s encoder blocks, which learns to respond to specific spatial conditions while preserving the original model’s generation capabilities. The preprocessor extracts a structural “control map” (a stick-figure pose, an edge outline, a depth gradient) from your reference image; ControlNet then injects that structure into every denoising step.
The split between preprocessor and model is the key idea: the preprocessor is a one-time analysis pass that turns your reference into a control map, and the ControlNet model is what conditions generation on that map. The same depth map can feed any depth ControlNet, and you can hand-author or edit a control map directly when a preprocessor gets it wrong.
Why ControlNet Doesn’t Break the Base Model: Zero Convolutions
The reason you can add ControlNet to a model without retraining or degrading it is a design detail called zero convolutions. ControlNet clones the encoder half of the frozen base model and connects that clone back into the original network through 1x1 convolution layers whose weights start at zero. At the very first training step those zero-initialized layers output nothing, so the combined network is identical to the original - then they gradually learn to inject the control signal.
This gives two practical guarantees:
- No catastrophic forgetting. The base model’s weights are frozen; only the trainable copy and the zero-convs learn. The model never “unlearns” what it already knew.
- Graceful start. Training begins from a perfect copy of the base model rather than from noise, so even small datasets produce usable controls.
This is also why a ControlNet is bound to its base family: the trainable copy mirrors that specific U-Net (or DiT), so its connection points only line up with a model of the same architecture.
Control Types at a Glance
Most workflows only need one control type. Pick it by what you want to preserve from the reference, not by what the reference is:
| You want to preserve… | Use | Preprocessor | Typical strength |
|---|---|---|---|
| A character’s pose | OpenPose / DWPose | dw_openpose_full |
0.8-1.0 |
| Exact edges and outlines | Canny | canny |
0.7-1.0 |
| Soft/organic shapes | SoftEdge | hed / pidinet |
0.5-0.8 |
| 3D spatial layout / depth | Depth | depth_anything / zoe |
0.5-0.8 |
| Straight architectural lines | MLSD | mlsd |
0.7-1.0 |
| A rough sketch → finished art | Scribble | scribble |
0.6-0.9 |
| Per-region scene semantics | Segmentation | seg_ofade20k |
0.5-0.8 |
| Structure during upscaling | Tile | tile_resample |
0.5-1.0 |
If you are unsure, Depth is the most forgiving general-purpose control (it constrains layout without locking in exact lines), and Canny is the most precise.
A Worked Example: Posing a Character
Suppose you have a reference photo of someone standing with arms crossed, and you want a knight in armor in that exact pose. The end-to-end flow with concrete settings:
- Preprocess the reference with
dw_openpose_fullat 1024px (SDXL). You now have a stick-figure skeleton - preview it and confirm the limbs are detected correctly. - Prompt for content and style only:
"a knight in ornate steel armor, dramatic studio lighting, photorealistic". Notice the prompt says nothing about pose - the control map handles that. - Apply an SDXL OpenPose ControlNet with
strength: 0.85,start_percent: 0.0,end_percent: 0.8. - Sample normally (e.g. DPM++ 2M, 30 steps, CFG 6).
The result is a knight standing with arms crossed. Ending control at 80% (end_percent: 0.8) lets the final steps add armor detail the skeleton never specified. If the pose drifts, raise strength toward 1.0; if the armor looks stiff or traced, lower strength or pull end_percent down to 0.6.
ControlNet Types in Depth
Each control type pairs a preprocessor (which extracts a specific structure from your reference) with a ControlNet model (which conditions on that structure). The sections below group them by what they capture. You rarely need more than one or two.
Pose Control
Pose controls extract a human skeleton from a reference and transfer it to your generated subject — the workhorse for character work.
| Preprocessor | What it captures | Notes |
|---|---|---|
| OpenPose | 18-25 body keypoints; optional hands and face | The original standard; variants are openpose_body, openpose_full, openpose_hand, openpose_face |
| DWPose | Whole-body skeleton including detailed hands/face | More accurate than OpenPose with better occlusion handling; the current recommended default |
| Animal OpenPose | Quadruped skeletons | For animals rather than humans |
Pose is keypoint-based, so it constrains posture but not silhouette or clothing — leave those to the prompt. If hands come out malformed, prefer a full/DWPose variant so the hand keypoints are detected and conditioned.
Edge and Line Control
Edge controls preserve outlines and structure. They differ mainly in how literal the lines are — hard binary edges versus soft, artistic ones.
| Preprocessor | Edge style | Best for |
|---|---|---|
| Canny | Hard binary edges from a classic algorithm | Architecture, products, anything with clean outlines |
| SoftEdge (HED / PiDiNet) | Soft, natural edges | Organic subjects, artistic restyles where hard lines look traced |
| MLSD | Straight lines only | Buildings, interiors, technical drawings |
| Lineart / Anime Lineart | Clean extracted line art | Coloring/restyling line drawings, manga |
| Scribble | Tolerant of rough, sketchy input | Turning a quick doodle into finished art |
Canny exposes low/high thresholds: a lower low threshold keeps more (fainter) edges, a higher high threshold keeps only the strongest. The practical rule is to pick by how literal you want the structure — Canny for “trace this exactly,” SoftEdge for “follow these shapes loosely,” Scribble for “use this as a hint.”
Depth Control
Depth controls capture the 3D layout of a scene as a grayscale map (near = bright, far = dark), constraining spatial arrangement without locking exact outlines. This makes depth the most forgiving general-purpose control.
| Preprocessor | Type | Notes |
|---|---|---|
| Depth Anything (v1/v2) | Relative depth | Current default — fast, robust, trained on a very large dataset; good for batch and video |
| MiDaS | Relative depth | The long-standing baseline; still fine for general use |
| ZoeDepth | Metric depth | Estimates actual distances; better for realistic outdoor scenes |
| LeReS | Relative depth | Higher quality on complex scenes, slower |
Start with Depth Anything. Depth pairs especially well with a second control (e.g. OpenPose) because it adds spatial grounding without fighting the pose.
Semantic and Surface Control
These conditions describe what occupies each region or how surfaces face, rather than edges or skeletons.
| Preprocessor | Captures | Best for |
|---|---|---|
| Segmentation (ADE20K) | A color-coded map of 150+ object classes | Laying out scenes (“sky here, building there”) |
| Normal map | Surface orientation as RGB-encoded normals | Lighting/relief consistency on products and sculptures |
With segmentation you can hand-paint the control map directly: each class has a fixed color (sky, building, tree, person, ground, etc.), so painting blocks of those colors dictates where each kind of object appears.
Utility Controls
A few controls solve specific production problems rather than transferring structure from a reference:
| Control | Purpose |
|---|---|
| Tile | Adds coherent detail during upscaling and enables seamless tiled generation — the backbone of high-res “Ultimate SD Upscale” workflows |
| Inpaint | Restricts generation to a masked region for clean object removal or editing |
| Shuffle | Reshuffles content spatially while preserving style — for creative variations |
Installation and Setup
ComfyUI Installation
# Install ControlNet models
cd ComfyUI/models/controlnet
# Download models (example for SD 1.5)
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_openpose.pth
wget https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11f1p_sd15_depth.pth
# For SDXL ControlNet
wget https://huggingface.co/diffusers/controlnet-canny-sdxl-1.0/resolve/main/diffusion_pytorch_model.fp16.safetensors
# Install preprocessor nodes
cd ../../custom_nodes
git clone https://github.com/Fannovel16/comfyui_controlnet_aux.git
Required Components
You need three things to run ControlNet, plus optional extras:
- Preprocessor nodes —
comfyui_controlnet_auxprovides the OpenPose, Canny, Depth, and other extractors. - ControlNet model(s) — one per control type, matched to your base-model family.
- A base diffusion model — your SD 1.5, SDXL, or FLUX checkpoint.
Optionally, add custom preprocessors or additional ControlNet models as your workflows grow.
Basic Workflows
The Single-ControlNet Graph
A ControlNet workflow extends the standard text-to-image graph by inserting one node between the text conditioning and the sampler. The control map flows in alongside the prompt:
flowchart LR
LI["LoadImage<br/>(reference)"] --> Pre["Preprocessor<br/>(pose / canny / depth)"]
Pre --> Apply["Apply ControlNet"]
Pos["CLIPTextEncode<br/>(positive)"] --> Apply
CN["Load ControlNet model"] --> Apply
Apply -->|conditioning| KS["KSampler"]
KS --> VD["VAE Decode"] --> SI["SaveImage"]
Everything before Apply ControlNet is the new branch; everything after is the ordinary sampler-to-image path. Preview the preprocessor output before sampling — most pose, edge, and depth failures are visible in the control map itself.
Stacking Two Controls
To combine controls (for example, a pose plus its scene depth), chain the Apply ControlNet nodes — the conditioning flows through each in turn:
flowchart LR
P1["OpenPose map"] --> A1["Apply ControlNet<br/>(pose, strength 0.9)"]
Pos["Positive conditioning"] --> A1
A1 --> A2["Apply ControlNet<br/>(depth, strength 0.5)"]
P2["Depth map"] --> A2
A2 --> KS["KSampler"]
Keep the secondary control weaker than the primary so they cooperate rather than fight. Two is plenty; three or more usually conflict.
The Parameters That Matter
Every Apply ControlNet node exposes the same handful of dials:
| Parameter | Range | What it does |
|---|---|---|
strength |
0-2 (use ~0.6-1.0) | How hard the control map pushes the result toward its structure |
start_percent |
0.0-1.0 | Fraction of sampling at which control begins (usually 0.0) |
end_percent |
0.0-1.0 | Fraction at which control stops (lower it to free up late detail) |
control_mode |
balanced / prompt / control | Whether to favor the prompt or the control map when they disagree |
The two most useful beyond strength are start_percent and end_percent. Because early denoising steps fix composition and later steps fill in detail, ending control early (e.g. end_percent: 0.7) lets the structure lock in the layout, then frees the model to add detail the control map never specified — often the difference between a rigid, traced-looking image and a natural one.
Common pitfalls:
- Mismatched ControlNet and base model. An SD 1.5 ControlNet silently fails or corrupts output on SDXL/FLUX. Match the family first.
- Strength pinned at 1.0. Full strength makes results look traced and fights the prompt. Start around 0.7 and raise only if structure drifts.
- Wrong preprocessor for the input. Running Canny on a soft watercolor produces noisy edges; use SoftEdge. Always preview the control map before sampling.
- Control resolution mismatch. Preprocess at the model’s native resolution (512 for SD 1.5, 1024 for SDXL) or the map misaligns with the latent.
- Stacking too many controls. Three or more ControlNets usually conflict and degrade quality. Prefer one strong control plus IP-Adapter for style.
Advanced Techniques
Combining Controls Deliberately
Two controls work best when each owns a different job. Give the primary control (the one carrying your main intent) full strength and the secondary one a supporting weight:
| Combination | Roles | Suggested strengths |
|---|---|---|
| Pose + Depth | Pose owns posture; depth grounds spatial layout | OpenPose ~0.9, Depth ~0.5 |
| Canny + Segmentation | Edges own outlines; segmentation owns region content | Canny ~0.8, Seg ~0.6 |
| Depth + SoftEdge | Depth owns 3D layout; soft edges add gentle shape | Depth ~0.7, SoftEdge ~0.4 |
If a stacked result looks muddy, lower the secondary control before touching the primary one.
Strength Scheduling with end_percent
You do not need per-step strength curves — the built-in start_percent/end_percent window is the practical version of scheduling. Holding control through the first ~70% of steps locks composition, then releasing it lets the model add detail freely. Reach for an early end_percent (0.5-0.7) whenever a result looks traced or stiff.
Control Mode Selection
When the prompt and the control map disagree, control_mode decides who wins:
| Mode | Behavior | Use case |
|---|---|---|
| Balanced | Weighs prompt and control roughly equally | General use (default) |
| Prompt (My prompt is more important) | Lets the prompt override structure when they conflict | Creative freedom, looser adherence |
| Control (ControlNet is more important) | Enforces the structure even against the prompt | Exact composition matching |
Resolution Matching
Always preprocess at your base model’s native resolution — 512 for SD 1.5, 1024 for SDXL/FLUX — so the control map aligns with the latent grid. A mismatch shifts the structure relative to the image and is one of the most common causes of “the pose is slightly off.”
Preprocessing Best Practices
The control map is only as good as the preprocessor that made it. Two habits prevent most problems: preview every control map before sampling, and match the preprocessor to the input, not just to the control type you want.
| Input quality | Recommended choice |
|---|---|
| Clean photo | Standard preprocessor for the type (Canny, OpenPose, Depth Anything) |
| Noisy or low-light | Robust variants — DWPose for pose, ZoeDepth/LeReS for depth |
| Artistic / painterly | Soft variants — SoftEdge (HED/PiDiNet) instead of Canny |
| Technical drawing | Precise variants — MLSD for straight lines |
You can also author or edit a control map by hand. Because the ControlNet only sees the map (not your reference), you can clean up a misdetected pose skeleton, paint a segmentation layout directly, or composite two maps together before sampling — often faster than rerolling preprocessor settings.
Model Compatibility
A ControlNet is built for one base-model family and only works there. Support and maturity vary widely across families:
- SD 1.5 ControlNet: The most mature ecosystem — every control type, heavily optimized
- SDXL ControlNet: Full support at higher resolution and quality
- SD3 ControlNet: Available (Canny, Depth, and others released by Stability AI)
- FLUX: Available — multiple options now ship, including ControlNet Union (one model covering several control types) and dedicated Canny/Depth/Pose models from teams such as XLabs, InstantX, and Shakker Labs
Beyond the structural controls, the ecosystem has added more specialized conditions over time — for example Recolor (change colors while preserving structure), Brightness/Illumination (steer lighting), and QR/pattern controls that hide scannable codes or shapes inside artistic images. Availability differs by base model; the structural types above are the universally supported core.
ControlNet Versions
ControlNets are tied to their base-model family. A control map is portable, but the ControlNet model is not — an SD 1.5 ControlNet will not load on SDXL or FLUX.
| Base Model | ControlNet Family | File Pattern |
|---|---|---|
| SD 1.5 | v1.1 (most complete) | control_v11*_sd15_*.pth |
| SD 2.1 | v1.1 SD2 | control_v11*_sd21_*.pth |
| SDXL | SDXL v1 / Union | controlnet-*-sdxl-1.0*.safetensors |
| SD3 | SD3 (Canny, Depth, …) | *controlnet*sd3*.safetensors |
| FLUX | FLUX / Union | *flux*controlnet*.safetensors |
Union models simplify the mess. Newer “ControlNet Union” releases for SDXL and FLUX bundle many control types into a single model file, so you load one ControlNet and select the mode (pose, canny, depth, …) at runtime instead of juggling a separate file per type.
ControlNet vs. the Alternatives
ControlNet is the most precise spatial conditioner, but it is not always the right tool. Several lighter or differently-focused methods share the space:
| Method | Conditions on | Strength | Best for |
|---|---|---|---|
| ControlNet | Structural map (pose, edge, depth) | Highest spatial precision | Reproducing exact composition |
| T2I-Adapter | Same map types, lighter | Fast, low VRAM, less precise | Real-time, batch, mobile |
| IP-Adapter | A reference image’s style/content | Transfers look, not layout | “Make it look like this” |
| InstantID | A reference face | Identity-preserving portraits | Consistent faces from one photo |
A common pattern is to combine them: ControlNet for where (structure), IP-Adapter for what it looks like (style), and a LoRA for who/what (subject). They condition on different things, so they cooperate rather than conflict.
T2I-Adapter
T2I-Adapter is a lighter alternative that conditions on the same kinds of maps (pose, edge, depth) but with a much smaller model. It trades a little precision for speed and low VRAM:
- Advantages: tiny model (~80 MB vs ~1.4 GB), faster inference, lower VRAM, several adapters combine cleanly — good for real-time and batch.
- Trade-offs: sometimes less precise than ControlNet, fewer available types, and may need more prompt help to lock the result.
Reach for T2I-Adapter when throughput or memory matters more than pixel-exact structure.
IP-Adapter Integration
IP-Adapter and ControlNet condition on different things, so they layer naturally: ControlNet from a depth map fixes the 3D structure, while IP-Adapter from a reference image supplies the style and palette. The result is precise composition wearing the look of your reference — neither alone achieves both.
Common Workflows
A few recurring jobs and the control setup each calls for:
| Goal | Reference | Preprocessor | Strength | Prompt handles |
|---|---|---|---|---|
| Character in a chosen pose | Pose photo | OpenPose / DWPose | ~0.9 | Outfit, style, setting |
| Render from a floor plan / line drawing | Technical drawing | MLSD (straight lines) | ~1.0 | Materials, lighting, mood |
| Restyle a photo, keep composition | The photo | Depth (+ SoftEdge) | Depth ~0.7, SoftEdge ~0.5 | The new style |
| Sketch to finished art | Rough sketch | Scribble | ~0.7 | Subject details, finish |
For character consistency across many images, fix the seed and pair a character LoRA (subject) with a pose ControlNet (posture) — the LoRA keeps the identity stable while the control map varies the pose.
Troubleshooting
Most ControlNet problems trace back to a bad control map or too-aggressive strength. Diagnose by previewing the map first, then adjust strength and the control window:
| Symptom | Likely cause | Fix |
|---|---|---|
| Preprocessor misses the subject (no skeleton/edges) | Low contrast, wrong preprocessor, low-res input | Raise contrast, switch to a robust variant (DWPose, SoftEdge), or hand-edit the map |
| Result looks traced or stiff | Strength too high, control runs too late | Lower strength toward 0.6, pull end_percent to ~0.7, optionally raise CFG |
| Harsh artifacts along edges | Canny on a soft/organic subject | Use SoftEdge instead, or lightly blur the control map |
| Structure is slightly misaligned | Control map resolution ≠ model resolution | Preprocess at 512 (SD 1.5) or 1024 (SDXL/FLUX) |
| Control silently does nothing / corrupts output | ControlNet built for a different base family | Use a ControlNet matching your checkpoint’s family |
Performance and VRAM
ControlNet adds a second pass over the encoder, so it costs memory and time. To keep it light: run the preprocessor on CPU (it is a one-time analysis pass and rarely the bottleneck), keep the ControlNet model on GPU, enable your tool’s low-VRAM / offload mode so unused models leave VRAM, and prefer T2I-Adapter when you need many controls cheaply.
Creative Applications
ControlNet’s value compounds once you stop treating the control map as fixed:
- Hybrid maps. Because the model only sees the map, you can composite two sources — e.g. take depth from a photo and edges from a separate sketch, blend them, and feed the combination — to borrow structure from multiple references at once.
- Restyle while preserving layout. Run Depth (and optionally SoftEdge) on a photo, then prompt for a completely different style (“oil painting in the style of Van Gogh”). The scene’s geometry survives while the look changes entirely.
- Animation consistency. For video, extract a control map per frame and blend each frame’s map slightly toward the previous one, so the conditioning evolves smoothly instead of jumping — a simple but effective way to reduce flicker. See Output Formats and Advanced Techniques for full temporal workflows.
Best Practices
Do
- Match control resolution to model resolution
- Use the appropriate preprocessor for the input type
- Experiment with strength values
- Combine multiple controls thoughtfully
- Save successful control maps for reuse
Avoid
- Using 100% control strength by default
- Ignoring prompt importance
- Mixing incompatible model versions
- Expecting perfect results immediately
- Overstacking controls (3+ is rarely helpful)
Where ControlNet Is Heading
A few directions are already shipping or clearly underway, rather than speculative:
- Union models that fold many control types into one file (SDXL and FLUX) are becoming the norm, replacing the old one-file-per-type sprawl.
- Better, faster preprocessors — Depth Anything for depth and DWPose for pose are recent examples — keep raising control-map quality, which matters more than new control types.
- Temporal/video control is maturing alongside video diffusion, addressing the frame-to-frame flicker that frame-by-frame ControlNet causes.
- Optical-illusion and pattern controls (hidden text, QR codes, spiral illusions) show how creatively the conditioning map can be repurposed.
The durable takeaway: invest in understanding the preprocessor-plus-model split and strength tuning, since those skills carry over to whatever control types arrive next.
Conclusion
ControlNet transforms diffusion models from probabilistic generators into precision tools. By understanding the various control types and their optimal applications, you can achieve unprecedented control over AI image generation while maintaining the creative capabilities of the base models.
The key to mastery is experimentation: try different preprocessors, adjust strengths, and combine controls creatively. As the technology evolves, ControlNet continues to bridge the gap between artistic vision and AI capabilities.
Key Takeaways
- ControlNet adds spatial control to diffusion by injecting a structural “control map” (pose, edge, depth, segmentation) into every denoising step.
- The preprocessor matters as much as the model — choose it to match your input (OpenPose for figures, Canny for edges, Depth for 3D structure).
- Strength is a dial, not a switch. Rarely use 100%; tune
strengthand pullend_percentback so structure guides the layout without overriding the prompt’s detail. - Combine deliberately: ControlNet for structure + IP-Adapter for style + a LoRA for subject — but stacking 3+ ControlNets rarely helps.
- Match versions and resolution. Use ControlNets built for your base family (SD1.5/SDXL/FLUX) and align control resolution with generation resolution.
See Also
- Stable Diffusion Fundamentals - Understanding the base generation process
- ComfyUI Guide - Integrate ControlNet into advanced workflows
- LoRA Training - Combine LoRAs with ControlNet for custom styles
- Advanced Techniques - Multi-control and expert patterns
- Model Types - ControlNet model types and compatibility
- Base Models Comparison - ControlNet support across models
- AI/ML Documentation Hub - Complete AI/ML documentation index