Reflex Docs
Guides

Deploy a custom model

Deploy any HuggingFace model as a hosted inference endpoint — your fine-tune or a public checkpoint, no build step.

Deploy any model from a HuggingFace repo — your own fine-tune or a public checkpoint — and serve it on Reflex's hosted GPUs. Known architectures (pi0.5) run on our optimized engine; anything else runs through generic HF transformers. No Docker, no build step, no separate "prepare" job — the worker pulls the model straight from HF the first time it wakes.

1. Deploy

import reflex

c = reflex.Client(api_key="rfx_...")

r = c.models.deploy(
    "your-org/your-finetune",   # any HF repo
    hf_token="hf_...",          # only for private repos
    architecture="pi05",        # optional; auto-detected from the repo otherwise
)
assert r["ok"], r               # deploy can be rejected (e.g. quota) → r is {ok: false, reason}
model_id = r["modelId"]         # e.g. "ks71nwyt..." — poll and connect with this

deploy() returns immediately with {"ok": true, "modelId": "...", "status": "provisioning"}. Behind the scenes Reflex provisions a scale-to-zero endpoint for your model — you never touch RunPod, Docker, or a GPU directly.

2. Wait until it's ready

The first cold start takes a few minutes while the image and your model download.

import time

while True:
    s = c.models.deploy_status(model_id)
    print(s["status"])                 # provisioning -> verifying -> ready | failed
    if s["status"] in ("ready", "failed"):
        break
    time.sleep(10)

if s["status"] == "failed":
    print("deploy failed:", s.get("detail"))
StatusMeaning
provisioningThe endpoint is being created.
verifyingYour model is downloading + running a one-shot self-test.
readyThe model loaded and served — you can run inference.
failedSomething went wrong; detail says what.

The endpoint is scale-to-zero: it costs nothing while idle. The first call after an idle period pays one cold start (a few minutes); calls to a warm endpoint are sub-second.

3. Connect to your model

Once it's ready, drive it with the same reflex connect flow as any model — just put your model_id in the target block:

# robot.yaml
target:
  kind: webrtc
  model_id: ks71nwyt...        # the modelId from deploy()
  connect_timeout_s: 180       # allow for the cold start
# hardware: ...                # same as the Quickstart
# cameras:  ...
reflex connect --config robot.yaml

Setting model_id routes the session to your deployed model (it defaults base_model to custom and the hosted serverless runtime). Everything else — hardware, cameras, the runner loop — is identical to connecting to a built-in model. Your model is scoped to your organization; only your org can route to it.

4. Tear it down

c.models.delete(model_id)   # deletes the endpoint; stops billing

How the architecture is chosen

Reflex looks at your repo and picks an engine automatically:

  • pi0.5 (repo named *pi05*/*pi0*, or a matching config.json) → our optimized openpi engine.
  • Everything else → the generic HF-transformers path (AutoModel / AutoModelForVision2Seq / AutoModelForCausalLM, resolved from the repo's config.json).

Pass architecture="pi05" to force the curated engine — useful for a pi0.5 fine-tune whose repo name doesn't contain pi05.

Tokens

  • Public repo → no token needed.
  • Private repo → pass hf_token. Your token reads your private repo, and for pi0.5 it also fetches the gated PaliGemma base the architecture is built on (any pi0.5 fine-tuner's HF account already has that access).

Your token is only forwarded into the endpoint's runtime environment. It is never stored, returned, or logged.

Optional model I/O

For generic models you can override the observation/action schema and prompting:

c.models.deploy(
    "your-org/openvla-finetune",
    state_dim=7, action_dim=7, chunk_size=1, control_hz=5,
    cameras=["base_0_rgb"],
    unnorm_key="bridge_orig",           # dataset norm stats for the action head
    prompt_template="In: What action...\nOut:",
)

API reference

CallReturns
client.models.deploy(hf_repo, *, hf_token=None, architecture=None, state_dim=None, action_dim=None, chunk_size=None, control_hz=None, cameras=None, unnorm_key=None, prompt_template=None, region=None){ok, modelId, status}
client.models.deploy_status(model_id){ok, status, detail?}
client.models.delete(model_id){ok, status}

Next