Nodes/TiledUpscale/Tiled Upscale & Refine
ComfyUI Node

Tiled Upscale & Refine

The node that lets FLUX.2 klein go far past its native resolution — without the grid of seams

By GianlucaMancuso·Created 2 months ago·Updated 16 days ago· 12
Tiled Upscale & Refine
  • model
  • positive
  • negative
  • vae
  • image
  • clip
  • image
  • info
◄upscale_by1.00►
◄tile_size0►
◄overlap0►
◄feather1.00►
◄seed0►
◄steps4►
◄cfg1.0►
◄sampler_nameeuler►
◄schedulersimple►
◄denoise1.00►
◄sequential_contexttrue►
◄color_match▾►
◄color_match_strength0.80►
◄final_color_matchtrue►
◄reference_modeauto►
◄prompt►
◄grounding_px768►
◄redo_first_tiletrue►

FLUX.2 klein does edits like nothing else you can run locally - fast, detailed, the default open editor for most people in 2026. But it natively tops out around 1–2MP, and upscaling a generation doesn't add detail, it adds blur. Tiled Upscale & Refine fixes that: it upscales your image, slices it into overlapping tiles, regenerates each tile at full tile resolution, and blends everything back into one image. The author's own example goes from 1920×1088 to 7968×4512 - 36 megapixels, 15 tiles - with joins you'd have to hunt for. That's the pitch: Klein's detail, arbitrarily beyond Klein's resolution.

It ships in the same pack as Tile Grid Advisor (the size math) and the manual Tile Split / Tile Merge pair - but this is the one you'll actually run.

Why this is different from every other tiled upscale

Old-school tiling - Ultimate SD Upscale, Tiled Diffusion - has a known failure: each tile is generated separately, so every one invents its own lighting, tint and detail, and you see the grid even after blending. That's not a cosmetic bug, it's the default outcome, and it's why people have spent years bolting ControlNet Tile onto tiled upscales.

This node sidesteps the problem with the trick Klein is built for: reference-latent editing. Each tile is encoded to a latent and attached as a reference_latent on the conditioning - the same thing the ReferenceLatent node does - so the model is told "refine this crop," not "invent a tile here." You feed it a plain CLIPTextEncode conditioning and the per-tile reference latent is handled internally. No ReferenceLatent, EmptyLatent or KSampler wiring, no SplitSigmas hacks - the fiddly part is done, and done carefully.

Second trick: sequential_context (on by default). Each tile is cropped from the canvas of tiles already generated, so it continues real neighbouring pixels instead of regenerating that region blind. That's what keeps a face or a line that crosses a tile boundary lining up.

The inputs that matter

Most of the KSampler fields are exactly what they look like. The ones worth your attention:

  • upscale_by - how much to scale the source before tiling (Lanczos). 1.0 = refine at current size.
  • tile_size - the resolution each tile is regenerated at, and the VRAM lever. 1024 is a safe default; the README reports it runs fine at 2048 on that 36MP example.
  • overlap - how much neighbouring tiles share. Wider = smoother joins, more tiles, slower. 192 is a solid start.
  • sequential_context - leave it on; only turn it off if you want every tile regenerated independently.
  • color_match / color_match_strength - per-tile colour matching back to the source crop (mkl by default), which stops tiles drifting apart in exposure or tint - and doubles as the fix for Klein's known warm cast on edits. final_color_match adds one more pass over the finished image.

The sampler defaults - 4 steps, CFG 1, euler, simple - are the Klein-distilled settings, so for a distilled model you can just hit run. Base models want more steps and higher CFG. Outputs are image (the finished upscale) and info - a string listing the grid actually used and each tile's position and real overlap. Worth a glance; that's how you find out your "16 tiles" turned out to be 15.

Installing it

ComfyUI Manager: search ComfyUI-TiledUpscale, install, restart. Or by hand:

cd ComfyUI/custom_nodes
git clone https://github.com/GianlucaMancuso/ComfyUI-TiledUpscale
cd ComfyUI-TiledUpscale
pip install -r requirements.txt   # just "color-matcher"

No model files - it works with whatever model, VAE and conditioning you have, and the example workflow uses only core nodes besides this pack. That one dependency matters: without color-matcher the node doesn't crash, it logs a "colour matching is disabled" warning and silently skips the colour matching - then your tiles drift apart in exposure and you'll think the blending is broken. It isn't. Install the requirement.

Where people get burned

  • Missing color-matcher - see above; the console warning is the tell.
  • Visible seams - the blend fade comes from the real overlap, not the requested one, so a low feather leaves a hard 50/50 band where two tiles fully overlap. Keep feather near 1; widen overlap if joins still show.
  • Grids cutting through a face or hand - each tile is its own generation, and two separately-generated halves have to agree. sequential_context and a wider overlap help a lot.
  • VRAM - tile_size is the knob. If a 1024 tile OOMs on your card, drop it; you pay in tile count, not correctness.

One honest caveat: this is a new pack with almost no community footprint yet - well-documented, lightly battle-tested. If you've been getting moiré-grid flashbacks from old tiled upscales, this is the modern Klein-era answer, and it works.

CategoryTiled Upscale

Inputs (24)

NameTypeDefaultDescription
modelMODEL—
positiveCONDITIONING—
negativeCONDITIONING—
vaeVAE—
imageIMAGE—
upscale_byFLOAT1.001–8—
tile_sizeINT00–4096Resolution each tile is regenerated at. 0 picks one from the output size: about four tiles along the longest side, kept between 1024 and 1536. Raise it by hand for fewer seams if you have the VRAM, keeping in mind that cost grows with the square of the tile.
overlapINT00–2048How much neighbouring tiles share. 0 picks 30% of the tile size: a tile drifts from its neighbours over roughly the outer 15% of its width, and an overlap band is where two tile edges meet, so it has to be wide enough that the middle of the band is outside both edge zones. Depends on the tile, not on upscale_by.
featherFLOAT1.000–1—
seedINT00–18446744073709550000—
stepsINT41–10000—
cfgFLOAT1.00–100—
sampler_nameCOMBOeuler44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38
schedulerCOMBOsimple9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3
denoiseFLOAT1.000–1—
sequential_contextBOOLEANtrue—
color_matchCOMBO7 options: mkl, hm, reinhard, mvgd, hm-mvgd-hm, hm-mkl-hm, +1
color_match_strengthFLOAT0.800–1—
final_color_matchBOOLEANtrue—
reference_modeoptCOMBOautoHow each tile is handed to the model as its own reference. 'conditioning' is the reference-latent path FLUX.2, Qwen and the Krea 2 style-reference LoRA use. 'in_context' prepends the tile as clean source tokens inside the model's forward, which is what the Krea 2 edit LoRAs are trained on. 'auto' picks in_context for Krea 2 and conditioning for everything else.
clipoptCLIPKrea 2 only, and only in the in_context mode. Connect the Krea 2 CLIP to re-encode the prompt per tile with that tile as the text encoder's vision input, the semantic half the edit LoRAs are trained with. Overrides the 'positive' input. Without it the model gets no image grounding and tends to ignore the reference entirely.
promptoptSTRINGThe instruction to encode per tile. Only used when 'clip' is connected.
grounding_pxoptINT7680–4096Longest side of the tile fed to the text encoder; 0 keeps the tile's own resolution. Lower favours edit adherence, higher favours likeness.
redo_first_tileoptBOOLEANtrueRegenerate the top-left tile once more at the end, when the tiles around it are finished. The first tile is otherwise the only one generated without any refined neighbour to continue from, which is what makes it sharpen backgrounds or hallucinate detail the other tiles don't. Costs one extra tile of sampling time; needs sequential_context.

Outputs (2)

NameTypeDescription
imageIMAGE—
infoSTRING—