Nodes/SDXL Adherence/Smart Latent
ComfyUI Node

Smart Latent

Latents at any size, without the OOM roulette

By regiellis·Created about a year ago·Updated 12 months ago· 10
Smart Latent
  • vae
  • image
  • latent
  • dims_json
  • width
  • height
  • bbox_json
mode
width1024
height1024
resolutionUse width/height
snap_modepad_up
pad_kindreflect
pad_value128
batch1
tile_size320
tile_overlap32
force_bchwtrue
use_tiledtrue
seed0
max_pixels1048576
max_long_side0

Most people find this node when their SDXL workflow OOMs at an unusual resolution, or when they type 1346×902 into Empty Latent and get back an image that looks subtly wrong. Smart Latent is the pack's answer to both: it creates empty latents or encodes images at any H×W, snaps everything safely to 64-multiples, and wraps the VAE so tiled encode/decode kicks in automatically when your VAE supports it. It's the workhorse of the SDXL Adherence pack (regiellis/ComfyUI-SDXL-Adherence) and the node the other helpers orbit.

SDXL doesn't like off-grid sizes - anything not on the 64 grid gets silently squished, and big canvases on a 24 GB card blow up VRAM. Smart Latent's whole job is to make "any size in, safe size out" a one-node operation.

How it works

mode picks between empty (allocate a blank latent - new images) and encode_image (VAE-encode a reference image for img2img or inpaint). In empty mode, the resolution dropdown has the standard SDXL presets (1024×1024, 1216×832, 1344×768, the lot), and selecting one overrides width/height. Then the snapping policies kick in:

  • pad_up (default) - letterbox to the next 64-multiple. Keeps all content, which is why it's the recommended default.
  • downscale_only - fit inside the nearest 64, then pad the small residual.
  • resize_round - resize near the nearest 64; changes aspect a bit.
  • crop_center - centered crop down to the lower 64, no resize.

Padding is alpha-aware - the RGB channels pad with your chosen pad_kind (reflect by default, with an automatic fallback to replicate when reflect would be illegal), while alpha pads with replicate/constant so you don't get halos. And max_pixels (default 1024×1024) acts as the VRAM ceiling: if your requested size exceeds it, the node downscales by 64-steps until it fits. max_long_side is a second, optional guard that pre-shrinks the input image before snapping.

The tiled VAE part is where it earns its keep: it probes several encode_tiled/decode_tiled signatures and falls back to plain encode/decode if your VAE doesn't have them. Bigger images on the same card, fewer OOMs.

Inputs and outputs

You set four things in practice: vae, mode, width, height - plus resolution if you'd rather click a preset. The rest (tile_size, tile_overlap, max_pixels, max_long_side, pad_*, batch, seed) are guardrails and tuning you only touch when something breaks.

Outputs: latent goes to the KSampler. width/height are the actual snapped dims, dims_json is metadata, and bbox_json is the critical one - it records where your real content sits inside the padded canvas, so Crop By BBox can cut the padding back off after decode. Keep bbox_json wired straight through.

Installing it

Same single install as the rest of the pack:

cd ComfyUI/custom_nodes
git clone https://github.com/regiellis/ComfyUI-SDXL-Adherence

Restart ComfyUI, or search "SDXL Adherence" in ComfyUI Manager. No model downloads, no dependencies beyond what ComfyUI already ships.

Troubleshooting

  • OOM at high res. Drop tile_size from 320 toward 256, lower max_pixels, or set max_long_side to cap the input. The pack's own speed notes suggest exactly this.
  • Latent mismatch errors. The node asserts the encoded latent is exactly W/8 × H/8. If you get a mismatch, you've fed it a VAE whose tiled path returns something unexpected - switch use_tiled off and see if it clears.
  • Padding you didn't ask for. pad_up is the default for a reason, but if you want no letterboxing at all, resize_round or crop_center avoid it. And whatever you choose, remember the decode comes back padded too - finish with Crop By BBox.

This is the one node in the pack you could reasonably call essential. Everything else is polish; Smart Latent is the plumbing.

Categoryitsjustregi / SDXL Adherence

Inputs (17)

NameTypeDefaultDescription
vaeVAEVAE model used to create or encode latents.
modeCOMBOCreate an empty latent or encode an input image.
widthINT102464–4096Requested width; may downscale by 64s to respect max_pixels.
heightINT102464–4096Requested height; may downscale by 64s to respect max_pixels.
resolutionoptCOMBOUse width/heightQuick presets; selecting one overrides width/height (empty mode).
snap_modeoptCOMBOpad_upSnap policy for non-64 dims: pad, downscale, resize, or crop.
pad_kindoptCOMBOreflectPadding type for pad_up/downscale (reflect avoids seams). 'edge' behaves like 'replicate'.
pad_valueoptINT1280–255Pad value (constant mode only).
batchoptINT11–16Batch size for empty latent or image batch.
imageoptIMAGEImage tensor when mode = encode_image.
tile_sizeoptINT320192–512Tile size for VAE.encode_tiled if available.
tile_overlapoptINT320–256Tile overlap for tiled VAE encode/decode.
force_bchwoptBOOLEANtrueEnsure image is [B,C,H,W] before encoding.
use_tiledoptBOOLEANtrueUse tiled VAE encode/decode when available.
seedoptINT0Reserved for future use.
max_pixelsoptINT104857665536–16777216Upper bound on W*H; uniformly downscale to fit if exceeded.
max_long_sideoptINT00–8192Optional VRAM guard: if >0, downscale input image so max(H,W) <= this before snapping.

Outputs (5)

NameTypeDescription
latentLATENT
dims_jsonSTRING
widthINT
heightINT
bbox_jsonSTRING