Save Intermediate Steps
Stream every sampling step to your frontend
- model
- model
If you've ever built a web frontend around ComfyUI, you know the drill: user hits "generate", and your UI shows a loading spinner for 30 seconds. This node fixes that specific pain. SaveIntermediateSteps wraps your model, saves a preview image after every sampling step, and writes a progress.json your frontend can poll - step number, percent, and the latest image, plus an optional base64 version if you don't want to deal with serving files. It's the closest thing ComfyUI has to A1111's "save intermediate images" extension, which people have been asking for since 2022.
It's MIT-licensed, has zero extra dependencies, and needs no model downloads. You can't ask for a much better first custom node.
How it actually works
The node doesn't sit between the sampler and the VAE like you might expect. It wraps the model: you take the MODEL from your checkpoint/UNET loader, pass it through this node, and feed the output into your sampler instead. Under the hood it clones the model and monkey-patches its apply_model method, so after every denoising step it reconstructs what the image should look like at that point (the "denoised" x0 estimate) and decodes it.
That decode is the clever part: it uses ComfyUI's own built-in latent_preview module, which is TAESD-based. So no VAE decode, no memory spike, no extra model files - these are the same cheap little previews ComfyUI already shows in its preview panel, just persisted to disk. The code handles both prediction styles, so it works across the model divide the community keeps tripping on: epsilon-prediction models (SD 1.5, SDXL) use x0 = x - sigma·eps, and flow-matching models like Flux use the model's own denoised calculation. That flow support was added in a Jan 2026 update, and it matters - this is one of the few intermediate-step savers that doesn't assume you're on SDXL.
What you actually set
Only two inputs are required, and one of them is trivial:
- model - from your checkpoint loader, into your sampler. Required, obviously.
- steps - your total sampling steps, used purely for the progress math in
progress.json. Set it to whatever your KSampler uses.
The optional ones are the fun part:
- job_id - an ID for this run. It becomes the folder name under
output/progress/, so the same run can be found by a later node or polled by your frontend. Leave it blank and the node generates a timestamp folder instead. - output_folder / filename_prefix - base folder name (default
progress) and file prefix (defaultstep). - format -
jpeg(default, quality 85) orpng. - include_base64 - set this if you want
progress.jsonto carry the latest frame as a base64 string instead of you serving image files.
Output: a single model wire that goes into your sampler. That's the whole graph:
Load Checkpoint → [Save Intermediate Steps] → KSampler → ...
Installation
ComfyUI Manager is the easy path - search for "ComfyUI-SaveIntermediates" and hit install. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/DanielBartolic/ComfyUI-SaveIntermediates.git
Then restart ComfyUI. That's it - the repo has no requirements.txt and pulls nothing extra; it leans on ComfyUI's bundled latent_preview (TAESD) and the Python standard library.
Where people get burned
Two things, both grounded in the actual code. First, the README's polling example checks for status === 'completed' - but the finalize() method that writes that status is never called. Your progress.json will say "generating" right up until the end. Poll on progress_percent === 100 (or just detect a stable file list) instead, or your frontend will spin forever.
Second, set expectations about image quality: these are TAESD previews, small and a little soft, not full-res VAE decodes. Great for progress bars and timelapses, wrong tool if you need pixel-accurate frames - that's what the VAE is for. And if you're generating video latents, the node only saves the first frame of each step. Fine for showing "it's working", not a frame-accurate video preview.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| steps | INT | 201–1000 | — |
| job_idopt | STRING | — | |
| output_folderopt | STRING | progress | — |
| filename_prefixopt | STRING | step | — |
| formatopt | COMBO | jpeg | 2 options: jpeg, png |
| include_base64opt | BOOLEAN | false | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| model | MODEL | — |