ComfyUI Sampler Configuration and Scheduling: A Complete Technical Guide

ComfyUI separates the sampler algorithm (the ODE/SDE integrator) from the noise schedule (sigma values), with the KSampler class in comfy/samplers.py orchestrating both components at runtime.

ComfyUI's sampling pipeline is a two-layer architecture that decouples the numerical integration method from the noise schedule generation. Understanding how sampler configuration and scheduling interact is essential for customizing diffusion workflows in the Comfy-Org/ComfyUI repository. The system uses modular handlers and factory functions to assemble these components dynamically based on UI selections.

Sampler Selection: Mapping Names to Algorithms

The sampler determines the numerical method used to solve the diffusion ODE or SDE. ComfyUI implements a factory pattern to resolve sampler names into executable functions.

sampler_object(name) serves as the primary factory function in comfy/samplers.py (lines 100-112). It accepts a string identifier such as "euler", "dpm_fast", or "uni_pc" and returns a KSAMPLER instance. This object wraps the low-level sampling function imported from k_diffusion.sampling and stores any extra options or inpaint-specific configurations.

The KSAMPLER class (lines 28-55 in comfy/samplers.py) inherits from the base Sampler class and holds the concrete sampler_function attribute. Its sample() method prepares the model wrapper, initializes noise tensors, and invokes the wrapped function. Supported identifiers are maintained in the SAMPLER_NAMES list (lines 22-27), which acts as a whitelist for the UI dropdown.

Scheduler Configuration: Generating Sigma Schedules

While the sampler defines how to step through the diffusion process, the scheduler defines when by producing the sigma (σ) values that control noise levels.

SCHEDULER_HANDLERS (lines 78-90 in comfy/samplers.py) maps human-readable names like "simple", "karras", and "ddim_uniform" to SchedulerHandler objects. Each handler encapsulates a scheduling function and a flag indicating whether it requires the full model_sampling object (use_ms=True) or raw (n, sigma_min, sigma_max) arguments.

Concrete implementations include:

  • simple_scheduler (lines 5-12): Linear interpolation between sigma max and min
  • ddim_scheduler (lines 84-88): Uniform steps compatible with DDIM sampling
  • normal_scheduler (lines 131-151): Standard log-normal spacing used by many legacy models

The calculate_sigmas function (lines 92-100) looks up the appropriate handler and returns a torch.FloatTensor of sigma values. The KSampler.calculate_sigmas method extends this with logic to discard penultimate sigmas for specific samplers (like dpm_2 and uni_pc) and applies user-defined denoise factors that truncate the schedule.

End-to-End Sampling Execution

When a workflow node executes, the system follows this precise pipeline:

  1. Configuration: The KSampler class stores the selected sampler and scheduler names during initialization.
  2. Sigma Generation: KSampler.calculate_sigmas builds the sigma tensor by querying SCHEDULER_HANDLERS and invokes the scheduling function.
  3. Sampler Instantiation: sampler_object() creates the KSAMPLER wrapper around the low-level function (e.g., k_diffusion_sampling.sample_euler).
  4. Conditioning Preparation: The sampling_function in comfy/samplers.py merges positive and negative conditionings and applies classifier-free guidance via cfg_function.
  5. Iteration: The low-level sampler in comfy/k_diffusion/sampling.py iterates over the sigma list, computing denoised predictions and advancing the latent state using the appropriate ODE/SDE step.

Practical Code Examples

Creating a KSampler Programmatically

import torch
from comfy.samplers import KSampler, sampler_object

device = torch.device("cuda")
steps = 20
sampler_name = "euler"
scheduler_name = "karras"

# Initialize the high-level KSampler

k = KSampler(model, steps, device, sampler=sampler_name, scheduler=scheduler_name)

# Generate noise and sample

noise = torch.randn(1, 4, 64 // 8, 64 // 8, device=device)
latent = k.sample(noise, positive, negative, cfg=7.5, seed=42)

This example demonstrates how KSampler.__init__ automatically calls calculate_sigmas to build the schedule, while k.sample handles the CFGGuider instantiation and conditioning preparation.

Adding a Custom Scheduler

from comfy.samplers import SCHEDULER_HANDLERS, SchedulerHandler
import torch

def my_linear_scheduler(model_sampling, steps):
    sigma_max = model_sampling.sigma_max
    sigma_min = model_sampling.sigma_min
    return torch.linspace(sigma_max, sigma_min, steps + 1)

# Register with use_ms=True to receive model_sampling object

SCHEDULER_HANDLERS["my_linear"] = SchedulerHandler(my_linear_scheduler)

# Use in subsequent KSampler instances

k = KSampler(model, steps=30, device=device, sampler="dpm_fast", scheduler="my_linear")

Inspecting Generated Sigma Values

k = KSampler(model, steps=10, device=device, sampler="euler", scheduler="ddim_uniform")
print(k.sigmas)  # Shape [11], ending with 0.0

Key Source Files

Understanding the repository structure helps navigate the codebase:

  • comfy/samplers.py: Core dispatcher containing KSampler, sampler_object, calculate_sigmas, SAMPLER_NAMES, SCHEDULER_HANDLERS, and CFG handling logic.
  • comfy/sampler_helpers.py: Utilities for conditioning preparation (process_conds, prepare_sampling), model loading bookkeeping, and memory estimation.
  • comfy/k_diffusion/sampling.py: Low-level diffusion step implementations including sample_euler, sample_heun, and sample_dpm_2.
  • comfy/model_sampling.py: Provides the ModelSampling object supplying sigma_min, sigma_max, and percent_to_sigma utilities used by schedulers.

Summary

  • ComfyUI sampler configuration relies on sampler_object() to map names to KSAMPLER instances that wrap low-level ODE/SDE solvers.
  • Scheduling is handled by SCHEDULER_HANDLERS, which dispatch to functions like simple_scheduler or karras_scheduler to generate sigma tensors.
  • The KSampler class orchestrates both components, managing sigma calculation, classifier-free guidance, and the iterative sampling loop.
  • Custom schedulers register via SchedulerHandler objects in SCHEDULER_HANDLERS for immediate integration with existing samplers.
  • Low-level sampling algorithms reside in comfy/k_diffusion/sampling.py, completely decoupled from schedule generation logic.

Frequently Asked Questions

What is the difference between a sampler and a scheduler in ComfyUI?

A sampler is the numerical algorithm that solves the diffusion equation (such as Euler or DPM-Solver), while a scheduler generates the sequence of noise levels (sigma values) that the sampler uses to guide the denoising process. The sampler determines how to step, and the scheduler determines where to step in the noise space.

How do I add a custom noise scheduler to ComfyUI?

Define a function that accepts model_sampling and steps arguments and returns a torch.FloatTensor of sigma values. Wrap this function in a SchedulerHandler with use_ms=True and register it in SCHEDULER_HANDLERS under a unique name. The scheduler becomes immediately available to all KSampler instances without modifying core code.

Where are the low-level sampling algorithms implemented in ComfyUI?

The actual diffusion step implementations reside in comfy/k_diffusion/sampling.py, which contains functions like sample_euler, sample_heun, and sample_dpm_2. These functions operate on the sigma schedule provided by KSampler and are wrapped by the KSAMPLER class for integration with ComfyUI's conditioning and guidance systems.

How does ComfyUI handle classifier-free guidance (CFG) during sampling?

CFG is applied in the sampling_function within comfy/samplers.py before the sampler executes each step. The system uses cfg_function to combine positive and negative conditionings based on the user-provided cfg scale, then passes the conditioned prediction to the low-level sampler algorithm for the actual latent update.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →