Skip to main content
Before your model can generate frames for users, it needs to be instantiated. This is the phase where your model’s weights are loaded into memory, pipelines are initialized, and everything is prepared for real-time generation. This happens once when the runtime starts, not once per user. This distinction is crucial: weight loading happens at instantiation, not when a user connects. When a user starts a session, your model is already warm and ready to generate frames immediately. When that user leaves, the model stays loaded for the next user. Think of it like a self-driving taxi that’s always running. Passengers get in and out, but the car never turns off.

The Model Decorator

Every Reactor model is identified by the @model decorator. This decorator tells Reactor what your model is and how to find its configuration.
from reactor_runtime import VideoModel, model

@model(name="my-diffusion-model", config="configs/default.yaml")
class MyVideoModel(VideoModel):
    def __init__(self, config):
        # Load weights here
        ...

    def start_session(self):
        # Generate frames here
        ...
The @model decorator requires one field:
  • name: A unique identifier for your model. This is how your model is known in the Reactor ecosystem (used in logs, deployments, and URLs). Pick something descriptive like "my-diffusion-model" or "world-sim-v2".
For a complete reference of all decorator fields, see Model Decorator.

Model Configuration

Before we look at the constructor, let’s understand how configuration flows into your model. Reactor allows YAML files for configuration. The configuration schema is completely up to you. You define whatever parameters your model needs. Reactor simply loads the YAML and passes it to your constructor. You specify a default config file path in the decorator’s config field:
@model(name="my-model", config="configs/default.yaml")
class MyVideoModel(VideoModel):
    ...
This is the factory configuration that ships with your model when it is built and deployed. Your YAML file can contain any parameters your model requires: resolution, inference steps, model paths, sampling parameters, or anything else:
# configs/default.yaml
num_steps: 5
resolution: 512
checkpoint_path: "./weights/model.safetensors"
compile: true
You can override any configuration value from the command line using --model.<key>=<value>:
reactor run --runtime http --model.num_steps=4
The configuration is passed to your model’s constructor as a DictConfig object from OmegaConf, which you can access like a dictionary:
def __init__(self, config: DictConfig):
    self.num_steps = config.get("num_steps", 5)
    self.resolution = config.get("resolution", 512)
    self.checkpoint_path = config.checkpoint_path
For details on configuration files, CLI overrides, and best practices, see Configuration.

The Model Constructor

When Reactor runs your model, it instantiates your class once. This is where all your heavy initialization should happen: loading weights, setting up pipelines, allocating GPU memory.
from reactor_runtime import VideoModel, model
from omegaconf import DictConfig

@model(name="my-diffusion-model", config="configs/default.yaml")
class MyVideoModel(VideoModel):
    def __init__(self, config: DictConfig):
        # This runs ONCE when the runtime starts.
        # Load your weights here.

        # Access configuration values
        self.num_steps = config.get("num_steps", 5)
        self.compile = config.get("compile", False)

        # Load your pipeline (the expensive part)
        print("Loading model weights...")
        self.pipeline = load_my_diffusion_pipeline(device="cuda")
        print("Weights loaded!")

    def start_session(self):
        # This runs every time a user connects.
        # The pipeline is already loaded.
        ...
Do not load weights in start_session(). That method is called every time a user connects. If you load weights there, users will wait for your model to load every single time, potentially minutes of waiting. Load everything in __init__ and store it in instance variables.

Model Lifecycle

Your model is instantiated once, but serves many sessions. When the first user connects, start_session() is called. When they disconnect, your cleanup code runs. When the next user connects, start_session() is called again, but __init__ is not called. Your weights are still loaded. Your pipeline is still warm. This is what makes Reactor efficient. A diffusion model might take 30 seconds to load during the preparation phase, but once loaded, every user gets instant model access. There is no cold start per user. For more on how sessions work, including how to ensure one user’s state does not leak to the next, see Sessions.
Now that you understand how models are loaded and instantiated, the next step is learning how your model can accept and react to real-time input from users.

Accepting User Inputs

Learn how to make your model react to real-time commands from users.