docs
CLI

Deploy apps

Package and ship a Python app to urun GPUs with urun deploy

urun deploy takes a Python entrypoint, packages the app, uploads it, and builds it on the control plane until the function is ready to serve sessions.

A minimal app

A uRun app is a Python file that creates an App and decorates one or more functions. The GPU shape lives on the @app.function decorator — it is deploy-time config, not something a session can override.

# app.py
import urun
from urun import App

app = App("hello-h100")

@app.function(gpus="h100:1")
def hello(ctx: urun.Context):
    print(f"running on {ctx.device}")
    return {"device": str(ctx.device)}

See the Python SDK for the full decorator surface (deps, credentials, multi-GPU gpus shapes like "b200:4", and session length via lease / max_session_s).

Deploy it

urun deploy app.py
Deploying hello-h100 (fa61f31b0961)
Files: 1 app, deps: pip
Uploading 3 missing blob(s)
Deployment queued: 7c9e1a...
Waiting for build to complete (--no-wait to skip)
ready

What urun deploy does

discover files  →  resolve deps  →  build manifest  →  register manifest
      →  upload missing blobs (content-addressed)  →  finalize  →  poll build
  1. Discover & resolve — finds the app's source files and resolves its declared dependencies.
  2. Manifest — builds a content-addressed manifest and registers it. The server replies with which blobs it already has.
  3. Upload — uploads only the blobs the server is missing (content-addressed, so re-deploys of unchanged files upload nothing).
  4. Finalize — finalizes the manifest, queuing the build.
  5. Poll — polls the build to readiness, printing progress. On failure the CLI prints the real build stderr so you can debug the image.

What ships

File discovery is automatic — there are no include flags:

  • The Python import closure of your entrypoint (every .py your app imports from the project).
  • Sibling data files — every non-.py file sitting in the same directory as a collected .py file ships too (a workflow_api.json, a prompt template, a small config read at import time). Data rides with its code: directories containing no collected code (weights/, node_modules/, media assets) contribute nothing, dotfiles and __pycache__ are excluded, and dependency metadata (requirements.txt, pyproject.toml, lockfiles) travels via the deps channel, never as data.
  • store.repo delta artifactsdiff= / overlay= files referenced by string literal are collected; a missing one is a hard error.

A .urunignore file excludes paths from collection (ignored code that the app imports fails loudly; ignored data is silently skipped). Ship large assets (weights, media) through the store, not the deploy bundle.

Flags

FlagDefaultEffect
--name NAMEderived from the entrypoint fileOverride the app name
--environment ENVresolved config or mainDeployment environment (alias --env)
--no-waitoffFinalize the deployment but don't poll for readiness
--poll-interval SECS2.0How often to poll the build status
--timeout SECS1800.0Give up polling after this many seconds
--api-url URLhttps://api.urun.sh/v1Control-plane base URL
--api-key KEYfrom env / saved loginDeploy API key

Fire-and-forget

To queue a build and return immediately (for example in CI where a later step watches status), skip the poll:

urun deploy app.py --no-wait

Then check readiness separately:

urun app status hello-h100

Use urun deploy. urun run is an alias: it accepts the same flags and runs the exact same deploy pipeline. Prefer urun deploy for clarity.

Next

On this page