Nodes/BrushNet/BrushNet
ComfyUI Node Runs on cloud

BrushNet

Bolt real inpainting onto any SD1.5/SDXL checkpoint, no dedicated model needed

By nullquant·Created 2 years ago·Updated about a year ago· 947
BrushNet
  • model
  • vae
  • image
  • mask
  • brushnet
  • positive
  • negative
  • model
  • positive
  • negative
  • latent
scale1.00
start_at0
end_at10000

Most inpainting tools ask you to swap checkpoints - load a dedicated Fill or Runway-style model trained specifically to paint inside a mask. BrushNet does the opposite. It's a dual-branch adapter that clips onto whatever checkpoint you're already using - your favorite realistic merge, your anime finetune, whatever - and teaches that model to inpaint without retraining it. Think of it as ControlNet's cousin: same idea of a side network feeding the frozen UNet extra signal, except the signal here is "here's exactly what the unmasked pixels look like, use them."

How it works

The BrushNet paper's trick is splitting the job into two branches instead of one. Most naive inpainting just concatenates the masked image into the latent and hopes the UNet figures it out, which is why plain checkpoints get seams and color drift. BrushNet instead runs the masked-image features through their own branch, hierarchically feeding that context into the frozen UNet at multiple layers, so the model always has a clean, pixel-level read on what's actually still there. That's the "decomposed dual-branch" bit in the paper title. The payoff, per the paper's own claims, is better mask-region preservation and text coherence than checkpoints with inpainting bolted on as an afterthought.

Where this sits in the wider 2026 inpainting landscape: it's neither a standard checkpoint doing img2img nor a purpose-trained Fill model - it's closer to the "graft inpainting onto any model" family that LanPaint and the newer union-ControlNet inpaint modes now occupy. BrushNet just got there first, in April 2024, before that category had a name.

Is it still worth using in 2026?

Honest answer: it's a 2024 tool and it shows. Reddit chatter about it spiked hard around its launch, stayed decent through 2024, and has been basically silent through 2026 - the community's attention moved to Flux Fill, crop-and-stitch workflows on instruction editors, and the newer union ControlNets' built-in inpaint modes. One user testing it against SDXL ControlNet and Flux Fill in mid-2025 reported "horrible results" with their SDXL setup. That doesn't mean it's broken - plenty of people got it working fine at launch and it still runs - but temper expectations and don't be surprised if a modern alternative outperforms it on a fresh SDXL checkpoint. Where it still earns its keep: pure SD1.5/SDXL local workflows where you don't want a second checkpoint's weights taking up VRAM, and it plays with LoRAs since the April 2024 rework.

Inputs and outputs

You'll set three things by hand, everything else is plumbing:

  • scale (default 1, range 0-10) - how strongly BrushNet's output gets added back into the UNet's residual. 1.0 is full strength; dial it down if the inpaint looks too aggressive.
  • start_at / end_at (default 0 / 10000) - the step window where BrushNet is active. Left alone, it's on for the whole run.

The rest are the sockets: model, vae, image, mask, brushnet (a BRMODEL from BrushNetLoader), and positive/negative conditioning. Outputs are model, positive, negative, and latent - wire model and latent straight into your KSampler, and the conditioning outputs pass through unchanged (the author's own words: they're used internally for the calculation, then "simply copied to output").

Installing it

ComfyUI Manager: search "BrushNet," install, restart. Manually: cd ComfyUI/custom_nodes && git clone https://github.com/nullquant/ComfyUI-BrushNet && pip install -r requirements.txt.

Then the model files, which is where people actually get stuck. Download BrushNet checkpoints from the pack's Google Drive link - segmentation_mask_brushnet_ckpt (trained on masks shaped like real objects) or random_mask_brushnet_ckpt (general, arbitrary mask shapes), each with SD1.5 and _sdxl_v0 SDXL versions. Drop the diffusion_pytorch_model.safetensors files into models/inpaint (or an inpaint entry in extra_model_paths.yaml).

Here's the landmine: every one of those downloads is literally named diffusion_pytorch_model.safetensors. Grab both the segmentation and random checkpoints and they'll silently overwrite each other unless you rename them first. The pack author's own community thread has people solving this by organizing subfolders - inpaint/brushnet/segmentation_mask.safetensors, inpaint/brushnet/random_mask.safetensors, and so on - before BrushNetLoader's dropdown can tell them apart at all.

Common issues

Two known incompatible nodes, straight from the README: WASasquatch's FreeU_Advanced and blepping's jank HiDiffusion. Both patch the same UNet functions BrushNet needs, so stacking either one in the same graph breaks things.

Model order matters. Any model-modifying nodes (LoRA loaders, etc.) need to go before BrushNet in the chain, not after. If you need the model for something downstream of BrushNet's inference - an upscale pass, say - use the original base model, not the BrushNet-patched one; latent upscaling between BrushNet and your KSampler doesn't work cleanly, a limitation of how BrushNet structurally hooks into the UNet.

Inconsistent SDXL results are a real, reported community experience, not a config mistake you're necessarily making - if your run looks bad, it's worth trying the other mask-shape checkpoint (segmentation vs. random) before assuming your setup is wrong.

Categoryinpaint

Inputs (10)

NameTypeDefaultDescription
modelMODEL
vaeVAE
imageIMAGE
maskMASK
brushnetBRMODEL
positiveCONDITIONING
negativeCONDITIONING
scaleFLOAT1.000–10
start_atINT00–10000
end_atINT100000–10000

Outputs (4)

NameTypeDescription
modelMODEL
positiveCONDITIONING
negativeCONDITIONING
latentLATENT